{"$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":"D5","name":"Coupling","shortDescription":{"text":"Coupling"},"helpUri":"https://codehealth.canine.dev/dimensions/D5"},{"id":"D6","name":"Cohesion (LCOM4)","shortDescription":{"text":"Cohesion (LCOM4)"},"helpUri":"https://codehealth.canine.dev/dimensions/D6"},{"id":"D8","name":"Code Coverage","shortDescription":{"text":"Code Coverage"},"helpUri":"https://codehealth.canine.dev/dimensions/D8"},{"id":"D9","name":"Test Distribution","shortDescription":{"text":"Test Distribution"},"helpUri":"https://codehealth.canine.dev/dimensions/D9"},{"id":"D10","name":"Test Quality","shortDescription":{"text":"Test Quality"},"helpUri":"https://codehealth.canine.dev/dimensions/D10"},{"id":"D11","name":"Test Reliability","shortDescription":{"text":"Test Reliability"},"helpUri":"https://codehealth.canine.dev/dimensions/D11"},{"id":"D12","name":"Dependency Hygiene","shortDescription":{"text":"Dependency Hygiene"},"helpUri":"https://codehealth.canine.dev/dimensions/D12"},{"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":"D14","name":"License Compliance","shortDescription":{"text":"License Compliance"},"helpUri":"https://codehealth.canine.dev/dimensions/D14"},{"id":"D15","name":"Churn \u00D7 Complexity Hotspots","shortDescription":{"text":"Churn \u00D7 Complexity Hotspots"},"helpUri":"https://codehealth.canine.dev/dimensions/D15"},{"id":"D16","name":"Bus Factor","shortDescription":{"text":"Bus Factor"},"helpUri":"https://codehealth.canine.dev/dimensions/D16"},{"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":"D37","name":"Vulnerability-disclosure Policy","shortDescription":{"text":"Vulnerability-disclosure Policy"},"helpUri":"https://codehealth.canine.dev/dimensions/D37","relationships":[{"target":{"id":"CWE-1059","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-1059"]}},{"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":"D44","name":"Platform End-of-Life","shortDescription":{"text":"Platform End-of-Life"},"helpUri":"https://codehealth.canine.dev/dimensions/D44"},{"id":"AC1","name":"Text alternatives","shortDescription":{"text":"Text alternatives"},"helpUri":"https://codehealth.canine.dev/dimensions/AC1"},{"id":"AC3","name":"Page structure","shortDescription":{"text":"Page structure"},"helpUri":"https://codehealth.canine.dev/dimensions/AC3"},{"id":"AC6","name":"Visual \u0026 motion safety","shortDescription":{"text":"Visual \u0026 motion safety"},"helpUri":"https://codehealth.canine.dev/dimensions/AC6"},{"id":"AC7","name":"A11y enforcement","shortDescription":{"text":"A11y enforcement"},"helpUri":"https://codehealth.canine.dev/dimensions/AC7"},{"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":"AX8","name":"Test isolation","shortDescription":{"text":"Test isolation"},"helpUri":"https://codehealth.canine.dev/dimensions/AX8"},{"id":"AX9","name":"CQS / query purity","shortDescription":{"text":"CQS / query purity"},"helpUri":"https://codehealth.canine.dev/dimensions/AX9"},{"id":"DM4","name":"Rich vs anemic domain model","shortDescription":{"text":"Rich vs anemic domain model"},"helpUri":"https://codehealth.canine.dev/dimensions/DM4"},{"id":"DM5","name":"Encapsulated state","shortDescription":{"text":"Encapsulated state"},"helpUri":"https://codehealth.canine.dev/dimensions/DM5"},{"id":"DM6","name":"Domain \u2194 infrastructure boundary","shortDescription":{"text":"Domain \u2194 infrastructure boundary"},"helpUri":"https://codehealth.canine.dev/dimensions/DM6"},{"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":"P4","name":"Deployment \u0026 Rollback","shortDescription":{"text":"Deployment \u0026 Rollback"},"helpUri":"https://codehealth.canine.dev/dimensions/P4"},{"id":"P6","name":"Release Hygiene","shortDescription":{"text":"Release Hygiene"},"helpUri":"https://codehealth.canine.dev/dimensions/P6"},{"id":"PF2","name":"Allocation hygiene","shortDescription":{"text":"Allocation hygiene"},"helpUri":"https://codehealth.canine.dev/dimensions/PF2"},{"id":"X10","name":"Duplicated predicate","shortDescription":{"text":"Duplicated predicate"},"helpUri":"https://codehealth.canine.dev/dimensions/X10"},{"id":"X29","name":"Per-element action decided by a fixed element","shortDescription":{"text":"Per-element action decided by a fixed element"},"helpUri":"https://codehealth.canine.dev/dimensions/X29"},{"id":"X32","name":"Type resolved by simple name across every loaded assembly","shortDescription":{"text":"Type resolved by simple name across every loaded assembly"},"helpUri":"https://codehealth.canine.dev/dimensions/X32"},{"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":"DonateCoordinator.presentActionSheet (cyclomatic 66): DonateCoordinator.presentActionSheet has cyclomatic complexity 66 (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":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":226}}}],"partialFingerprints":{"codehealthFindingId/v1":"8ed572e5238ee3b1976bc0d3b84bbab9f822c760b458ef248bbe8286c6601bfb"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFFont.\u0060for\u0060 (cyclomatic 65): WMFFont.\u0060for\u0060 has cyclomatic complexity 65 (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":"WMFComponents/Sources/WMFComponents/Style/WMFFont.swift"},"region":{"startLine":61}}}],"partialFingerprints":{"codehealthFindingId/v1":"f5abf8927fb0abd4a2c434d3e87f28feb782f6bc8cb304daa90780275bafc835"}},{"ruleId":"D1","level":"warning","message":{"text":"ReadingListsSyncOperation.processLocalUpdates (cyclomatic 55): ReadingListsSyncOperation.processLocalUpdates has cyclomatic complexity 55 (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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":479}}}],"partialFingerprints":{"codehealthFindingId/v1":"f845eecac88bcbe6bab01a0f321011069ceb4fbce7a6414c4b42dab0035804a3"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFAccountLoginLogoutFetcher.login (cyclomatic 54): WMFAccountLoginLogoutFetcher.login has cyclomatic complexity 54 (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":"Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift"},"region":{"startLine":89}}}],"partialFingerprints":{"codehealthFindingId/v1":"ab391fc0713c3b433bb58c7b630c5a9d8d0e4328b7da80fe255932e748b5b67f"}},{"ruleId":"D1","level":"warning","message":{"text":"PlacesViewController.regroupArticlesIfNecessary (cyclomatic 43): PlacesViewController.regroupArticlesIfNecessary has cyclomatic complexity 43 (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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":1449}}}],"partialFingerprints":{"codehealthFindingId/v1":"6ad6a18f4502ee930b5daf559e54ef91a345d88b3ee2c6e64eb61e35a6067216"}},{"ruleId":"D1","level":"warning","message":{"text":"Router.destinationForWikiResourceURL (cyclomatic 42): Router.destinationForWikiResourceURL has cyclomatic complexity 42 (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":"WMF Framework/Router.swift"},"region":{"startLine":54}}}],"partialFingerprints":{"codehealthFindingId/v1":"31ac4e80c8130a2a43db2885339dd61a274b4250cdd7433b0481c87a483d6e5d"}},{"ruleId":"D1","level":"warning","message":{"text":"PlacesViewController.adjustLayout (cyclomatic 42): PlacesViewController.adjustLayout has cyclomatic complexity 42 (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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":1829}}}],"partialFingerprints":{"codehealthFindingId/v1":"04033280ab4f9e3c6f6304f5a683682e42afb13045a75f49b369a11de0422e3c"}},{"ruleId":"D1","level":"warning","message":{"text":"Router.destinationForWResourceURL (cyclomatic 37): Router.destinationForWResourceURL has cyclomatic complexity 37 (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":"WMF Framework/Router.swift"},"region":{"startLine":163}}}],"partialFingerprints":{"codehealthFindingId/v1":"b1264c6c7c4e2d9e861f40deaee1df30068e930b141b544c0161255a460a4eb5"}},{"ruleId":"D1","level":"warning","message":{"text":"HtmlUtils.addStyling (cyclomatic 34): HtmlUtils.addStyling has cyclomatic complexity 34 (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":"WMFComponents/Sources/WMFComponents/Utility/HTMLUtils.swift"},"region":{"startLine":320}}}],"partialFingerprints":{"codehealthFindingId/v1":"f859eed7f7c330bcd90469213c7c8cae28a2a0f73b340fcb70f8b4d94fa4c3f0"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFWatchlistFilterViewModel.generateDataForNewFilterSettings (cyclomatic 34): WMFWatchlistFilterViewModel.generateDataForNewFilterSettings has cyclomatic complexity 34 (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":"WMFComponents/Sources/WMFComponents/Components/Watchlist/Filter/WMFWatchlistFilterViewModel.swift"},"region":{"startLine":140}}}],"partialFingerprints":{"codehealthFindingId/v1":"a935bee94948f33f5f227cf126482875345fbcd05f33adff999a6d3668a401b4"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFDatabaseHousekeeper.deleteStaleUnreferencedArticles (cyclomatic 33): WMFDatabaseHousekeeper.deleteStaleUnreferencedArticles has cyclomatic complexity 33 (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":"Wikipedia/Code/WMFDatabaseHousekeeper.swift"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"140298949547c79d434881b55601fe93996579b2af7c78c2a1c4d27954c87ced"}},{"ruleId":"D1","level":"warning","message":{"text":"ArticleCacheDBWriter.syncResources (cyclomatic 32): ArticleCacheDBWriter.syncResources has cyclomatic complexity 32 (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":"Wikipedia/Code/ArticleCacheDBWriter.swift"},"region":{"startLine":35}}}],"partialFingerprints":{"codehealthFindingId/v1":"31ccd4bcd03afa1d5f94e912bbb8492b075fa494ed3fa7b874e22cbf33280bd9"}},{"ruleId":"D1","level":"warning","message":{"text":"ReadingListsSyncOperation.locallyCreate (cyclomatic 31): ReadingListsSyncOperation.locallyCreate has cyclomatic complexity 31 (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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":756}}}],"partialFingerprints":{"codehealthFindingId/v1":"4ca4cd5a211eb7e38554e455c276bf4b4e84167b794e137f644c74fe8795005b"}},{"ruleId":"D1","level":"warning","message":{"text":"DetailTransition.animateTransition (cyclomatic 30): DetailTransition.animateTransition has cyclomatic complexity 30 (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":"Wikipedia/Code/DetailTransition.swift"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"d88c0d52bc15df34bdfd775335d42e15ef82bb1288f27e41459d3b1208e3498c"}},{"ruleId":"D1","level":"warning","message":{"text":"NotificationsCenterDetailViewModel.primaryAction (cyclomatic 30): NotificationsCenterDetailViewModel.primaryAction has cyclomatic complexity 30 (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":"Wikipedia/Code/NotificationsCenterDetailViewModel.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"17157f2a493138d54f3935d531297ae4b1de0f02b850617d9f8e1490bcf6ec25"}},{"ruleId":"D1","level":"warning","message":{"text":"ReadingListsCollectionViewCell.sizeThatFits (cyclomatic 30): ReadingListsCollectionViewCell.sizeThatFits has cyclomatic complexity 30 (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":"Wikipedia/Code/ReadingListsCollectionViewCell.swift"},"region":{"startLine":114}}}],"partialFingerprints":{"codehealthFindingId/v1":"66708befb74da62d0bc42f794b21f704e0d64bfcb10f8a051dad8333ca7e2ef5"}},{"ruleId":"D1","level":"warning","message":{"text":"CollectionViewUpdater.controllerDidChangeContent (cyclomatic 29): CollectionViewUpdater.controllerDidChangeContent has cyclomatic complexity 29 (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":"Wikipedia/Code/CollectionViewUpdater.swift"},"region":{"startLine":69}}}],"partialFingerprints":{"codehealthFindingId/v1":"e0639876e405abc58f2072383ca10146c27decc246d0bfb343f3d28da92cb4f9"}},{"ruleId":"D1","level":"warning","message":{"text":"AppOnboardingCoordinator.start (cyclomatic 28): AppOnboardingCoordinator.start has cyclomatic complexity 28 (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":"Wikipedia/Code/AppOnboardingCoordinator.swift"},"region":{"startLine":33}}}],"partialFingerprints":{"codehealthFindingId/v1":"0d2aeda4b005466a3a8524ef9acea43113f7b480aae2c44815d360a694434f4b"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFAppViewController.logWatchlistUserDidSaveFilterSettings (cyclomatic 28): WMFAppViewController.logWatchlistUserDidSaveFilterSettings has cyclomatic complexity 28 (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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":495}}}],"partialFingerprints":{"codehealthFindingId/v1":"914e89d812d3599b07a4878ab478ae55fc79547e3833206f22cd40aa4a9fede8"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFNavigationBarConfiguring.configureNavigationBar (cyclomatic 27): WMFNavigationBarConfiguring.configureNavigationBar has cyclomatic complexity 27 (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":"WMFComponents/Sources/WMFComponents/Extensions/Navigation Bar/WMFNavigationBarConfiguring.swift"},"region":{"startLine":119}}}],"partialFingerprints":{"codehealthFindingId/v1":"b0ef8b820b7e92c7e4d2158f192e374f5a2018e976a86c6987d0692c5a68fab8"}},{"ruleId":"D1","level":"warning","message":{"text":"ReadingListsSyncOperation.executeSync (cyclomatic 27): ReadingListsSyncOperation.executeSync has cyclomatic complexity 27 (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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":60}}}],"partialFingerprints":{"codehealthFindingId/v1":"be26af48be1439167e957b3d8e54d57810e82f78cbb7ce6b476fc83205cba25e"}},{"ruleId":"D1","level":"warning","message":{"text":"DescriptionEditViewController.save (cyclomatic 27): DescriptionEditViewController.save has cyclomatic complexity 27 (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":"Wikipedia/Code/DescriptionEditViewController.swift"},"region":{"startLine":342}}}],"partialFingerprints":{"codehealthFindingId/v1":"44131c5797461c2f926ca5674ccbbea270c1706428c72b4a23ffab920991fb82"}},{"ruleId":"D1","level":"warning","message":{"text":"DiffTransformer.populateAdditionalSectionAndMoveInfo (cyclomatic 27): DiffTransformer.populateAdditionalSectionAndMoveInfo has cyclomatic complexity 27 (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":"Wikipedia/Code/DiffTransformer.swift"},"region":{"startLine":99}}}],"partialFingerprints":{"codehealthFindingId/v1":"1136dc1e676e33c2650941ae5fbff1c5f69f2f93dd2acff83ff279f196facf0b"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFAppViewController.processUserActivity (cyclomatic 27): WMFAppViewController.processUserActivity has cyclomatic complexity 27 (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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":1319}}}],"partialFingerprints":{"codehealthFindingId/v1":"4ddfec7488979f195f4eac82519b7f61540e14cd688dd718bc280c4dc23cf43b"}},{"ruleId":"D1","level":"warning","message":{"text":"HomeCoordinator.makeHomeViewController (cyclomatic 26): HomeCoordinator.makeHomeViewController 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":"Wikipedia/Code/HomeCoordinator.swift"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"2bbdf18afa07f199f6cbb5d4281c071e254306f66a77f6e869e872b8d22f90b9"}},{"ruleId":"D1","level":"warning","message":{"text":"ViewControllerRouter.route (cyclomatic 26): ViewControllerRouter.route 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":"Wikipedia/Code/ViewControllerRouter.swift"},"region":{"startLine":89}}}],"partialFingerprints":{"codehealthFindingId/v1":"39949026e62845a24d76207b5aaabdb126d67eec9c51228b94c20222418a14f5"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFUserImpactDataController.fetch (cyclomatic 24): WMFUserImpactDataController.fetch has cyclomatic complexity 24 (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":"WMFData/Sources/WMFData/Data Controllers/Shared/WMFUserImpactDataController.swift"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"5821f756c81169ed975c8509101a60fbf341c966392355593fb4d8f363b2d2e8"}},{"ruleId":"D1","level":"warning","message":{"text":"NotificationsCenterCommonViewModel.verboseTitle (cyclomatic 24): NotificationsCenterCommonViewModel.verboseTitle has cyclomatic complexity 24 (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":"Wikipedia/Code/NotificationsCenterCommonViewModel.swift"},"region":{"startLine":10}}}],"partialFingerprints":{"codehealthFindingId/v1":"4b43431fcc837881693a456b8700dd3bae770066207ec9273f005874d68662e5"}},{"ruleId":"D1","level":"warning","message":{"text":"SavedArticlesFetcher.handleFailure (cyclomatic 24): SavedArticlesFetcher.handleFailure has cyclomatic complexity 24 (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":"Wikipedia/Code/SavedArticlesFetcher.swift"},"region":{"startLine":308}}}],"partialFingerprints":{"codehealthFindingId/v1":"eb2774a27d8a018ef5ac10dd70c274f12691f5d1f514cc65309de5ef200c573b"}},{"ruleId":"D1","level":"warning","message":{"text":"String.pluralDictionary (cyclomatic 24): String.pluralDictionary has cyclomatic complexity 24 (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":"WMF Framework/HasText.swift"},"region":{"startLine":83}}}],"partialFingerprints":{"codehealthFindingId/v1":"08bee7c2042bce79d460e941b9dc2118c8937d623048cbfeb7bca4f3c76c1271"}},{"ruleId":"D1","level":"warning","message":{"text":"PermanentlyPersistableURLCache.updateCacheWithCachedResponse (cyclomatic 23): PermanentlyPersistableURLCache.updateCacheWithCachedResponse has cyclomatic complexity 23 (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":"WMF Framework/PermanentlyPersistableURLCache.swift"},"region":{"startLine":452}}}],"partialFingerprints":{"codehealthFindingId/v1":"59436b6cffebac35c3f069d08c9dcd4abe423560167e78f6f2176d56d03330bc"}},{"ruleId":"D1","level":"warning","message":{"text":"ReadingListsSyncOperation.createOrUpdate (cyclomatic 23): ReadingListsSyncOperation.createOrUpdate 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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":914}}}],"partialFingerprints":{"codehealthFindingId/v1":"26e1655be866669c89ddf61967d9fa650aa1002f736fcae66276299d1c64963e"}},{"ruleId":"D1","level":"warning","message":{"text":"ArticlePeekPreviewViewController.contextMenuItems (cyclomatic 23): ArticlePeekPreviewViewController.contextMenuItems 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":"Wikipedia/Code/ArticlePeekPreviewViewController.swift"},"region":{"startLine":115}}}],"partialFingerprints":{"codehealthFindingId/v1":"33a8de77ef09a8723bf9cdf590fd9d5eabba7c896784ac0f5c052d9d8ec7502a"}},{"ruleId":"D1","level":"warning","message":{"text":"SavedArticlesCollectionViewCell.sizeThatFits (cyclomatic 23): SavedArticlesCollectionViewCell.sizeThatFits 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":"Wikipedia/Code/SavedArticlesCollectionViewCell.swift"},"region":{"startLine":134}}}],"partialFingerprints":{"codehealthFindingId/v1":"350cb911b30e552c5aefa3271b3df5429bf79d3cf785b1a7079a1d76a66e5e72"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFEditorInputView.didSelectIndex (cyclomatic 22): WMFEditorInputView.didSelectIndex has cyclomatic complexity 22 (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":"WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/Input Views/WMFEditorInputView.swift"},"region":{"startLine":419}}}],"partialFingerprints":{"codehealthFindingId/v1":"49185609de5ff044620efc4f1d1db6961ab0da618f9ad4e9935bd0e167bbd826"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFArticleTabsDataController.getAdjacentArticleInTab (cyclomatic 22): WMFArticleTabsDataController.getAdjacentArticleInTab 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":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":422}}}],"partialFingerprints":{"codehealthFindingId/v1":"2dc7bcb933f94cda9b33200354aa3e5a4604c49c2ea19dcb43277ec18e5e3b50"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFArticleSavedStateMigrationManager.migrateSyncedArticles (cyclomatic 22): WMFArticleSavedStateMigrationManager.migrateSyncedArticles 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":"WMF Framework/WMFArticle\u002BMigration.swift"},"region":{"startLine":201}}}],"partialFingerprints":{"codehealthFindingId/v1":"11e1ed3d3f3c42115ad5cebb2eeebf080c47974e52ecac9952c698ed1b70c2f1"}},{"ruleId":"D1","level":"warning","message":{"text":"WikipediaLanguageCommandLineUtility.getSiteInfoLookup (cyclomatic 22): WikipediaLanguageCommandLineUtility.getSiteInfoLookup has cyclomatic complexity 22 (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":"Command Line Tools/Update Languages/WikipediaLanguageCommandLineUtility.swift"},"region":{"startLine":72}}}],"partialFingerprints":{"codehealthFindingId/v1":"da1955490bb7b3df27b4ba95f38f8eeb93aaa921796ad67e2318e116f5060449"}},{"ruleId":"D1","level":"warning","message":{"text":"DiffContainerViewController.setupDiffListViewControllerIfNeeded (cyclomatic 22): DiffContainerViewController.setupDiffListViewControllerIfNeeded 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":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":882}}}],"partialFingerprints":{"codehealthFindingId/v1":"f14fdf3d9da2f25e7934d1fed94e3bb03139aea54951cd8336ee34db8b446958"}},{"ruleId":"D1","level":"warning","message":{"text":"EditorViewController.loadContent (cyclomatic 22): EditorViewController.loadContent has cyclomatic complexity 22 (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":"Wikipedia/Code/EditorViewController.swift"},"region":{"startLine":192}}}],"partialFingerprints":{"codehealthFindingId/v1":"836f3746f9b2b66c7d47f84a0b00eaee2047cebcde02f50655dc538a89ba9641"}},{"ruleId":"D1","level":"warning","message":{"text":"NotificationsCenterViewController.userDidPanCell (cyclomatic 22): NotificationsCenterViewController.userDidPanCell 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":"Wikipedia/Code/NotificationsCenterViewController.swift"},"region":{"startLine":778}}}],"partialFingerprints":{"codehealthFindingId/v1":"bbe9b879a5d3fe0bbb04c23d603db675e166d1ac0f998501e5297ad5f9ae5724"}},{"ruleId":"D1","level":"warning","message":{"text":"PlacesViewController.performSearch (cyclomatic 22): PlacesViewController.performSearch 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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":682}}}],"partialFingerprints":{"codehealthFindingId/v1":"596e14d18764494d146ec808adffccc462a59b7fef128c2020a0c210a1aff7c4"}},{"ruleId":"D1","level":"warning","message":{"text":"Session.request (cyclomatic 22): Session.request 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":"Wikipedia/Code/Session.swift"},"region":{"startLine":230}}}],"partialFingerprints":{"codehealthFindingId/v1":"0f4ae39fd7fdb58a9662442f69b5b13273348f8691e32d7ab2a1a2fb718094a9"}},{"ruleId":"D1","level":"warning","message":{"text":"TalkPageViewController.tappedPublish (cyclomatic 22): TalkPageViewController.tappedPublish 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":"Wikipedia/Code/TalkPageViewController.swift"},"region":{"startLine":1136}}}],"partialFingerprints":{"codehealthFindingId/v1":"166552cceade144c4998fca890c07ed9316b7fa4b36f925f910bce605cc9e969"}},{"ruleId":"D1","level":"warning","message":{"text":"HtmlUtils.addStyling (cyclomatic 21): HtmlUtils.addStyling has cyclomatic complexity 21 (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":"WMFComponents/Sources/WMFComponents/Utility/HTMLUtils.swift"},"region":{"startLine":168}}}],"partialFingerprints":{"codehealthFindingId/v1":"8f39f584fd5be51e44de0b8f2c38bd4cc0d4815594c83c4bfa467c79344c2a61"}},{"ruleId":"D1","level":"warning","message":{"text":"HtmlUtils.listInsertData (cyclomatic 21): HtmlUtils.listInsertData has cyclomatic complexity 21 (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":"WMFComponents/Sources/WMFComponents/Utility/HTMLUtils.swift"},"region":{"startLine":518}}}],"partialFingerprints":{"codehealthFindingId/v1":"d646fbb74f3574e85f08e0a8aeebeca670399554736ee0dcbfe9553b9ef7a605"}},{"ruleId":"D1","level":"warning","message":{"text":"EditSaveViewController.handleEditFailure (cyclomatic 21): EditSaveViewController.handleEditFailure has cyclomatic complexity 21 (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":"Wikipedia/Code/EditSaveViewController.swift"},"region":{"startLine":574}}}],"partialFingerprints":{"codehealthFindingId/v1":"e38d7bbd3c55e3fc76ff23d18728952833ac4ad72ec03725582c463ba996425c"}},{"ruleId":"D1","level":"warning","message":{"text":"TalkPageViewController.tappedPublish (cyclomatic 21): TalkPageViewController.tappedPublish has cyclomatic complexity 21 (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":"Wikipedia/Code/TalkPageViewController.swift"},"region":{"startLine":1231}}}],"partialFingerprints":{"codehealthFindingId/v1":"51b5628ea1000802c61257dac2977e8d8fb30e6fa0cf58ab49bbdabba01f884a"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFDailyGameExploreCell.sizeThatFits (cyclomatic 21): WMFDailyGameExploreCell.sizeThatFits has cyclomatic complexity 21 (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":"Wikipedia/Code/WMFDailyGameExploreCell.swift"},"region":{"startLine":226}}}],"partialFingerprints":{"codehealthFindingId/v1":"ae549b3264721c5d9ca3714dee43cc0b068392c046934b01c2c51b5d683e1ee1"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFWatchlistDataController.apply (cyclomatic 20): WMFWatchlistDataController.apply 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":"WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift"},"region":{"startLine":254}}}],"partialFingerprints":{"codehealthFindingId/v1":"106dfcf920f98089292256b97bb4cce04cfbcea2b3b15040757b065bfff10e40"}},{"ruleId":"D1","level":"warning","message":{"text":"ExploreCardCollectionViewCell.sizeThatFits (cyclomatic 20): ExploreCardCollectionViewCell.sizeThatFits 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":"WMF Framework/ExploreCardCollectionViewCell.swift"},"region":{"startLine":204}}}],"partialFingerprints":{"codehealthFindingId/v1":"ff5fb511c6da87a763d7079be0698716a8f2abbafe68c12459400442caf51edd"}},{"ruleId":"D1","level":"warning","message":{"text":"PageNamespace.isTalkBased (cyclomatic 20): PageNamespace.isTalkBased has cyclomatic complexity 20 (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. This is NOT this file\u0027s highest cyclomatic complexity: PageNamespace.stringValue (cyclomatic 44) is higher and carries no row of its own \u2014 it was excluded as a flat dispatcher (a long switch/match over independent cases: many branches, almost no nesting), which this dimension does not treat as a refactor obligation. It is named here so the ranking you see in this file is not mistaken for the whole of it; the excluded method is counted neither in this dimension\u0027s figures nor in its score."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/PageNamespace.swift"},"region":{"startLine":91}}}],"partialFingerprints":{"codehealthFindingId/v1":"32c47a5fd51e30808dcdd6af4a21be3946eae3ee2270ec871c2c899885cd9341"}},{"ruleId":"D1","level":"warning","message":{"text":"DiffListChangeItemViewModel.calculateAttributedString (cyclomatic 20): DiffListChangeItemViewModel.calculateAttributedString 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":"Wikipedia/Code/DiffListChangeItemViewModel.swift"},"region":{"startLine":302}}}],"partialFingerprints":{"codehealthFindingId/v1":"fa05c1572ff81ea4fc4d7a8dc9ba8d6cab89818ba0eda08f13756683749160c8"}},{"ruleId":"D1","level":"warning","message":{"text":"SchemeHandler.kickOffDataTask (cyclomatic 20): SchemeHandler.kickOffDataTask has cyclomatic complexity 20 (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":"Wikipedia/Code/SchemeHandler/SchemeHandler.swift"},"region":{"startLine":163}}}],"partialFingerprints":{"codehealthFindingId/v1":"a9fba561392e63a9354d01d0f45e02f6149718fff3271924840abd3cad3628a7"}},{"ruleId":"D1","level":"warning","message":{"text":"UIView.wmf_preferredFrame (cyclomatic 20): UIView.wmf_preferredFrame has cyclomatic complexity 20 (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":"WMF Framework/UIStackView\u002BSubviewVerification.swift"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"60ca03a28a92dc0e74c73a4a3a277fc5b3f7ec666dd47957f3f4047d11d1b570"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFActivityTabView.loggedInList (cyclomatic 19): WMFActivityTabView.loggedInList 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":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift"},"region":{"startLine":80}}}],"partialFingerprints":{"codehealthFindingId/v1":"70958f41749b24e3af8ff8ca9d40ac953ad0bd68c7f22e802ed155344a392b46"}},{"ruleId":"D1","level":"warning","message":{"text":"TimelineViewModel.fetch (cyclomatic 19): TimelineViewModel.fetch 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":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/TimelineViewModel.swift"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"323d320e9e24fd298849c828f64728033adb5a0c727f49c992b791c41eaaab46"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFAppViewControllerTipWrapper.listenForTooltips (cyclomatic 19): WMFAppViewControllerTipWrapper.listenForTooltips 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":"Wikipedia/Code/AppViewControllerTipWrapper.swift"},"region":{"startLine":28}}}],"partialFingerprints":{"codehealthFindingId/v1":"94e25fce5e02696126f52114c1d092426bd04a71dfbbf4de1449bcbf3771f6be"}},{"ruleId":"D1","level":"warning","message":{"text":"ArticleViewController.showFundraisingCampaignAnnouncementIfNeeded (cyclomatic 19): ArticleViewController.showFundraisingCampaignAnnouncementIfNeeded has cyclomatic complexity 19 (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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"fd5053359dc7fa2ee3ca828139537ece4d5e9d0cd7119aae81aaa1a24abab537"}},{"ruleId":"D1","level":"warning","message":{"text":"PageHistoryFetcher.fetchEditCounts (cyclomatic 19): PageHistoryFetcher.fetchEditCounts 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":"Wikipedia/Code/PageHistoryFetcher.swift"},"region":{"startLine":155}}}],"partialFingerprints":{"codehealthFindingId/v1":"5292139c6d693a6edd38cf65b52005b496f16fb36eb39d57d6793e82ad2eab90"}},{"ruleId":"D1","level":"warning","message":{"text":"PlacesViewController.updatePlaces (cyclomatic 19): PlacesViewController.updatePlaces 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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":843}}}],"partialFingerprints":{"codehealthFindingId/v1":"62208883ccae82c3f24b2485d5daa49c7530076300b1a10e158bac1250067d35"}},{"ruleId":"D1","level":"warning","message":{"text":"SavedArticlesFetcher._update (cyclomatic 19): SavedArticlesFetcher._update has cyclomatic complexity 19 (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":"Wikipedia/Code/SavedArticlesFetcher.swift"},"region":{"startLine":164}}}],"partialFingerprints":{"codehealthFindingId/v1":"a56dca458c9a14be593750e6abf86acb1a843f04aad903137334d18bb8d34e10"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFAuthenticationManager.loginWithSavedCredentials (cyclomatic 19): WMFAuthenticationManager.loginWithSavedCredentials 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":"Wikipedia/Code/WMFAuthenticationManager.swift"},"region":{"startLine":253}}}],"partialFingerprints":{"codehealthFindingId/v1":"4e1821ccf754cb896a105dfcbbcccda8e09aba6c44be12ae827be1e1f60027c9"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFHCaptchaViewController.setupHCaptcha (cyclomatic 19): WMFHCaptchaViewController.setupHCaptcha 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":"Wikipedia/Code/WMFHCaptchaViewController.swift"},"region":{"startLine":98}}}],"partialFingerprints":{"codehealthFindingId/v1":"82db3b7821e7de7bb873d63066b2ce9cda471e5369b2334cdbf7826b43bddd34"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFArticleTabsDataController.fetchAllArticleTabs (cyclomatic 18): WMFArticleTabsDataController.fetchAllArticleTabs 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":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":768}}}],"partialFingerprints":{"codehealthFindingId/v1":"32276ac819861cbe349957c086a6ba84d0cc4b63293a7339b135ebd599e682e8"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFExperimentsDataController.determineBucketForExperiment (cyclomatic 18): WMFExperimentsDataController.determineBucketForExperiment 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":"WMFData/Sources/WMFData/Data Controllers/Experiments/WMFExperimentsDataController.swift"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"1f5b381e0233d292e906d56d0b727f6e561acc4c03a7d35e82ec4e4ebb229291"}},{"ruleId":"D1","level":"warning","message":{"text":"ArticleCacheController.syncCachedResources (cyclomatic 18): ArticleCacheController.syncCachedResources has cyclomatic complexity 18 (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":"WMF Framework/ArticleCacheController.swift"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"34b592c32cb5439e18af0850df2b12282b94dc9c9d645d5b84b2f8ef773fab7a"}},{"ruleId":"D1","level":"warning","message":{"text":"MediaWikiFetcher.perform (cyclomatic 18): MediaWikiFetcher.perform 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":"WMF Framework/MediaWikiFetcher.swift"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"4c4342cdb82a0077dd78d01bcbf2420e1fe807d66eca46d913292bc7d7b9705b"}},{"ruleId":"D1","level":"warning","message":{"text":"ArticleTabCoordinating.trackArticleTab (cyclomatic 18): ArticleTabCoordinating.trackArticleTab 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":"Wikipedia/Code/ArticleCoordinator.swift"},"region":{"startLine":32}}}],"partialFingerprints":{"codehealthFindingId/v1":"96c97a8cd0dc8c4ed5eafd4b9c6df0708d4bf3df8311115e45b1f4721def7163"}},{"ruleId":"D1","level":"warning","message":{"text":"ArticleRightAlignedImageCollectionViewCell.sizeThatFits (cyclomatic 18): ArticleRightAlignedImageCollectionViewCell.sizeThatFits 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":"Wikipedia/Code/ArticleRightAlignedImageCollectionViewCell.swift"},"region":{"startLine":41}}}],"partialFingerprints":{"codehealthFindingId/v1":"fcf33e8a54ac531437931885b0c37fe76b9e850a2f17386906ad46b7239059d5"}},{"ruleId":"D1","level":"warning","message":{"text":"PageHistoryCollectionViewCell.sizeThatFits (cyclomatic 18): PageHistoryCollectionViewCell.sizeThatFits 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":"Wikipedia/Code/PageHistoryCollectionViewCell.swift"},"region":{"startLine":173}}}],"partialFingerprints":{"codehealthFindingId/v1":"93ce1cb1e06ca6629703338d1b756106ace7df6207ca52cd532b3e58935e2d26"}},{"ruleId":"D1","level":"warning","message":{"text":"localization.swift.importLocalizationsFromTWN (cyclomatic 18): localization.swift.importLocalizationsFromTWN 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":"Command Line Tools/Update Localizations/localization.swift"},"region":{"startLine":433}}}],"partialFingerprints":{"codehealthFindingId/v1":"b594d081ec63dd71b3b4b17c12e0df73f5aa8124884721d5d020af153a1af829"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFCommunityFeedView.feedList (cyclomatic 17): WMFCommunityFeedView.feedList has cyclomatic complexity 17 (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":"WMFComponents/Sources/WMFComponents/Components/Home/WMFCommunityFeedView.swift"},"region":{"startLine":39}}}],"partialFingerprints":{"codehealthFindingId/v1":"e79d54026989cdaf269f4fab6f1bef86148672d9d648d884067ddd698dab1cd2"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFBasicService.performPOST (cyclomatic 17): WMFBasicService.performPOST 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":"WMFData/Sources/WMFData/Service/WMFBasicService.swift"},"region":{"startLine":59}}}],"partialFingerprints":{"codehealthFindingId/v1":"1fa51605a12c4a0b52ca5db85bee2da3a3649cd89421a590114a1f95389af945"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFDonateDataController.submitPayment (cyclomatic 17): WMFDonateDataController.submitPayment has cyclomatic complexity 17 (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":"WMFData/Sources/WMFData/Data Controllers/Donor Experience/WMFDonateDataController.swift"},"region":{"startLine":204}}}],"partialFingerprints":{"codehealthFindingId/v1":"0fa3f1c2845e5e8b6ca41ccc87b0ab7f09584bd245ccfff47e31ee8fabbff01b"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFArticleDataController.fetchArticleInfo (cyclomatic 17): WMFArticleDataController.fetchArticleInfo 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":"WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleDataController.swift"},"region":{"startLine":102}}}],"partialFingerprints":{"codehealthFindingId/v1":"e0ea868acb8d08884c94b659ff5b999107a21895daaf2af20197d479ddc5713d"}},{"ruleId":"D1","level":"warning","message":{"text":"WikipediaLanguageCommandLineUtilityAPI.getSites (cyclomatic 17): WikipediaLanguageCommandLineUtilityAPI.getSites 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":"Command Line Tools/Update Languages/WikipediaLanguageCommandLineUtilityAPI.swift"},"region":{"startLine":22}}}],"partialFingerprints":{"codehealthFindingId/v1":"ac01900cb311cf4493a00437dadb06f152f9ca20cca99512f9c665b297cd5e51"}},{"ruleId":"D1","level":"warning","message":{"text":"RemoteNotificationsController.predicateForFilterSavedState (cyclomatic 17): RemoteNotificationsController.predicateForFilterSavedState has cyclomatic complexity 17 (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":"WMF Framework/Remote Notifications/RemoteNotificationsController.swift"},"region":{"startLine":404}}}],"partialFingerprints":{"codehealthFindingId/v1":"1afe74c23198cc4d4ed8258d39d6bfc384122ec371e43c5495132bad28cc8ba8"}},{"ruleId":"D1","level":"warning","message":{"text":"DonateCoordinator.nativeDonateFormViewModel (cyclomatic 17): DonateCoordinator.nativeDonateFormViewModel has cyclomatic complexity 17 (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":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":461}}}],"partialFingerprints":{"codehealthFindingId/v1":"004c6a71fe6de3385eed152adfaf7a2af1cb1c7d59bb55396200800340afa36f"}},{"ruleId":"D1","level":"warning","message":{"text":"DonateCoordinator.logNativeFormDidTriggerPaymentSuccess (cyclomatic 17): DonateCoordinator.logNativeFormDidTriggerPaymentSuccess has cyclomatic complexity 17 (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":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":872}}}],"partialFingerprints":{"codehealthFindingId/v1":"106c72bdc00477c5cf5928a80186df39a210ad1a1f0b91af5fea216eaa58df0e"}},{"ruleId":"D1","level":"warning","message":{"text":"ExploreViewController.collectionView (cyclomatic 17): ExploreViewController.collectionView 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":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":613}}}],"partialFingerprints":{"codehealthFindingId/v1":"01afd34912e9b786a8a7176c0a73281624a5a297e230360482ee887d2f795c4c"}},{"ruleId":"D1","level":"warning","message":{"text":"PageHistoryViewController.configure (cyclomatic 17): PageHistoryViewController.configure 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":"Wikipedia/Code/PageHistoryViewController.swift"},"region":{"startLine":458}}}],"partialFingerprints":{"codehealthFindingId/v1":"7d5c10b1181f0824a949a8ed061e2258f897b2dbd69eb4d144b80de44f626dc9"}},{"ruleId":"D1","level":"warning","message":{"text":"PlacesViewController.merge (cyclomatic 17): PlacesViewController.merge 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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":1402}}}],"partialFingerprints":{"codehealthFindingId/v1":"f7596a58833f7efbbdc54f7cbb875698e886a83a6c32482afb533bd69076a347"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFAppViewController.logTabBarSelectionsForActivityTab (cyclomatic 17): WMFAppViewController.logTabBarSelectionsForActivityTab has cyclomatic complexity 17 (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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":1261}}}],"partialFingerprints":{"codehealthFindingId/v1":"55a0d75df8bd070b53e0f53c3d01d6ed4af9f41b886223800dbb09ce49436244"}},{"ruleId":"D1","level":"warning","message":{"text":"WikimediaProject.init (cyclomatic 17): WikimediaProject.init has cyclomatic complexity 17 (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":"Wikipedia/Code/WikimediaProject.swift"},"region":{"startLine":92}}}],"partialFingerprints":{"codehealthFindingId/v1":"60af56655b0019ee87d83227d9bfef82617d9bbe98b765bcc812d51c18f07f07"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFWikitextUtils.insertImageWikitextIntoArticleWikitextAfterTemplates (cyclomatic 16): WMFWikitextUtils.insertImageWikitextIntoArticleWikitextAfterTemplates has cyclomatic complexity 16 (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":"WMFData/Sources/WMFData/Utility/WMFWikitextUtils.swift"},"region":{"startLine":150}}}],"partialFingerprints":{"codehealthFindingId/v1":"10279e4bf4f0c08312e76af627bb61bf44cedceb93298e5515b305ddd542b910"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFWatchlistDataController.fetchWatchlist (cyclomatic 16): WMFWatchlistDataController.fetchWatchlist has cyclomatic complexity 16 (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":"WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"a0eabc862b1437f1d61bcf835921a1de5847cb0c34a7521df0d527a4c4a27e78"}},{"ruleId":"D1","level":"warning","message":{"text":"CacheController.remove (cyclomatic 16): CacheController.remove has cyclomatic complexity 16 (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":"WMF Framework/CacheController.swift"},"region":{"startLine":290}}}],"partialFingerprints":{"codehealthFindingId/v1":"132d607fe534c59892c449354ae2ae4e8a5167206ebbe21b64835b0a6cf2e4bf"}},{"ruleId":"D1","level":"warning","message":{"text":"CollectionViewEditController.handlePanGesture (cyclomatic 16): CollectionViewEditController.handlePanGesture has cyclomatic complexity 16 (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":"WMF Framework/CollectionViewEditController.swift"},"region":{"startLine":264}}}],"partialFingerprints":{"codehealthFindingId/v1":"c60ff97370e21e2a91b6d294dbdada22fcec690802d0cb9d7175bdf6e54d84d5"}},{"ruleId":"D1","level":"warning","message":{"text":"ColumnarCollectionViewLayout.prepare (cyclomatic 16): ColumnarCollectionViewLayout.prepare has cyclomatic complexity 16 (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":"WMF Framework/ColumnarCollectionViewLayout.swift"},"region":{"startLine":190}}}],"partialFingerprints":{"codehealthFindingId/v1":"804c6d19172d2e6e8bd4889589f11a1304f04503fa7c3ed19c67c33d3bc18577"}},{"ruleId":"D1","level":"warning","message":{"text":"ReadingListsSyncOperation.createOrUpdate (cyclomatic 16): ReadingListsSyncOperation.createOrUpdate has cyclomatic complexity 16 (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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":1010}}}],"partialFingerprints":{"codehealthFindingId/v1":"337dec90a9fadf6ba23c22c590422fdaf9ceefccbf7eca49d48615a5a032b639"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFArticleSavedStateMigrationManager.runMigration (cyclomatic 16): WMFArticleSavedStateMigrationManager.runMigration has cyclomatic complexity 16 (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":"WMF Framework/WMFArticle\u002BMigration.swift"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"2c8f7302077a3532bd2d02c94aee38c9a825105a28381fdd16a6c536e3760162"}},{"ruleId":"D1","level":"warning","message":{"text":"WidgetController.fetchTopReadContent (cyclomatic 16): WidgetController.fetchTopReadContent has cyclomatic complexity 16 (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":"WMF Framework/Widget/WidgetController.swift"},"region":{"startLine":370}}}],"partialFingerprints":{"codehealthFindingId/v1":"b507ae89ddab450a69238fae8ac20e75148be18c7721ac92f60c9b41540e2e47"}},{"ruleId":"D1","level":"warning","message":{"text":"DiffContainerViewController.populatePrevNextModelsForToolbar (cyclomatic 16): DiffContainerViewController.populatePrevNextModelsForToolbar has cyclomatic complexity 16 (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":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":446}}}],"partialFingerprints":{"codehealthFindingId/v1":"8780b7f21199b10be29e7bcc00066478c36d654311b119b9e779754e2aa3d2b6"}},{"ruleId":"D1","level":"warning","message":{"text":"DiffContainerViewController.completeRollbackOrUndo (cyclomatic 16): DiffContainerViewController.completeRollbackOrUndo has cyclomatic complexity 16 (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":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":1291}}}],"partialFingerprints":{"codehealthFindingId/v1":"99969005c35c449d3b719eeb7a6e83dfe1a9e096af985e718a498998110a82bb"}},{"ruleId":"D1","level":"warning","message":{"text":"DonateCoordinator.logWebViewFormThankYouDidDisappear (cyclomatic 16): DonateCoordinator.logWebViewFormThankYouDidDisappear has cyclomatic complexity 16 (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":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":990}}}],"partialFingerprints":{"codehealthFindingId/v1":"1dcbc7b2fa06b7ee757c6b872d96e77c1c255fc208f85c31c4e4933e0d2de337"}},{"ruleId":"D1","level":"warning","message":{"text":"NotificationsCenterViewController.userDidTapMoreActionForCell (cyclomatic 16): NotificationsCenterViewController.userDidTapMoreActionForCell has cyclomatic complexity 16 (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":"Wikipedia/Code/NotificationsCenterViewController.swift"},"region":{"startLine":870}}}],"partialFingerprints":{"codehealthFindingId/v1":"a81e0a88835be689cfd40ade53a524db7bade9cccd4b1014c6498334fcae825f"}},{"ruleId":"D1","level":"warning","message":{"text":"PageHistoryViewController.getEditCounts (cyclomatic 16): PageHistoryViewController.getEditCounts has cyclomatic complexity 16 (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":"Wikipedia/Code/PageHistoryViewController.swift"},"region":{"startLine":189}}}],"partialFingerprints":{"codehealthFindingId/v1":"be41c0fb4b56db726d5e7ce0d999e9212a807cdaeb6aee070a28e59c2510288b"}},{"ruleId":"D1","level":"warning","message":{"text":"SavedAllArticlesCoordinator.fetchAllSavedArticles (cyclomatic 16): SavedAllArticlesCoordinator.fetchAllSavedArticles has cyclomatic complexity 16 (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":"Wikipedia/Code/SavedAllArticlesCoordinator.swift"},"region":{"startLine":435}}}],"partialFingerprints":{"codehealthFindingId/v1":"7fdad2a983563607464c1b9d0d2696c3f351c290b15da83c7202e5908255e846"}},{"ruleId":"D1","level":"warning","message":{"text":"SinglePageWebViewController.handleNavigation (cyclomatic 16): SinglePageWebViewController.handleNavigation has cyclomatic complexity 16 (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":"Wikipedia/Code/SinglePageWebViewController.swift"},"region":{"startLine":389}}}],"partialFingerprints":{"codehealthFindingId/v1":"210e61fa0539ddeb0601c79dc2ae037be90a614d64cc7090521cd7e5b96b816e"}},{"ruleId":"D1","level":"warning","message":{"text":"ThanksGiving.tappedThank (cyclomatic 16): ThanksGiving.tappedThank has cyclomatic complexity 16 (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":"Wikipedia/Code/ThanksGiving.swift"},"region":{"startLine":35}}}],"partialFingerprints":{"codehealthFindingId/v1":"96d6aa8a90ebae7b4c117831e341582aaf2e54c0cf6aaebd675c8fc697b2cfdd"}},{"ruleId":"D1","level":"warning","message":{"text":"WatchlistController.presentChooseExpiryActionSheet (cyclomatic 16): WatchlistController.presentChooseExpiryActionSheet has cyclomatic complexity 16 (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":"Wikipedia/Code/WatchlistController.swift"},"region":{"startLine":127}}}],"partialFingerprints":{"codehealthFindingId/v1":"911ed5f95ed6732fc12249822b243b6802046f74d885e3dc13dd6a600d198390"}},{"ruleId":"D1","level":"warning","message":{"text":"WikitextFetcher.fetchSection (cyclomatic 16): WikitextFetcher.fetchSection 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":"Wikipedia/Code/WikitextFetcher.swift"},"region":{"startLine":74}}}],"partialFingerprints":{"codehealthFindingId/v1":"2e1083c1ee3532009e53beb090bea0c671cc9334c08b03067923f119de508db1"}},{"ruleId":"D1","level":"warning","message":{"text":"WMFContentGroup.detailViewControllerWithDataStore (cyclomatic 16): WMFContentGroup.detailViewControllerWithDataStore has cyclomatic complexity 16 (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":"WMF Framework/WMFContentGroup\u002BDisplay.swift"},"region":{"startLine":34}}}],"partialFingerprints":{"codehealthFindingId/v1":"aba801561841abbad05938b9546a8ecfd0f37054236a2ae5c14902d9491305ad"}},{"ruleId":"D1","level":"warning","message":{"text":"GenerateTopicsStrings.swift.injectIntoStringsFile (cyclomatic 16): GenerateTopicsStrings.swift.injectIntoStringsFile has cyclomatic complexity 16 (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":"scripts/GenerateTopicsStrings.swift"},"region":{"startLine":291}}}],"partialFingerprints":{"codehealthFindingId/v1":"d106b2230427a1a3cb73d50507aa6d7606aa17206685d3e7bd1639f0a70955aa"}},{"ruleId":"D2","level":"warning","message":{"text":"ReadingListsSyncOperation.processLocalUpdates (cognitive 133): ReadingListsSyncOperation.processLocalUpdates has cognitive complexity 133 (threshold 15). Drivers by points: if/else 35 (93 pts), loops 17 (35 pts), boolean chains 5 (nesting depth added 76). 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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":479}}}],"partialFingerprints":{"codehealthFindingId/v1":"3d7b565a8fa60c84033fd32cd8d49715933f017a3a4160ae3d53c6e2c4be683b"}},{"ruleId":"D2","level":"warning","message":{"text":"PlacesViewController.regroupArticlesIfNecessary (cognitive 88): PlacesViewController.regroupArticlesIfNecessary has cognitive complexity 88 (threshold 15). Drivers by points: if/else 29 (66 pts), loops 9 (15 pts), boolean chains 5, ternaries 2 (nesting depth added 43). 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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":1449}}}],"partialFingerprints":{"codehealthFindingId/v1":"0cc9ff9710026073e1536c8d4625ddfab4cdb1d316949ab911ea44a0dd099794"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFAccountLoginLogoutFetcher.login (cognitive 87): WMFAccountLoginLogoutFetcher.login has cognitive complexity 87 (threshold 15). Drivers by points: if/else 28 (59 pts), boolean chains 22, match/switch 2 (6 pts) (nesting depth added 35). 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":"Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift"},"region":{"startLine":89}}}],"partialFingerprints":{"codehealthFindingId/v1":"c8a3eaef91a89a531ae8764d3c3dc853c17ea59c6a45521d5bd6b594257dfbce"}},{"ruleId":"D2","level":"warning","message":{"text":"DiffTransformer.populateAdditionalSectionAndMoveInfo (cognitive 67): DiffTransformer.populateAdditionalSectionAndMoveInfo has cognitive complexity 67 (threshold 15). Drivers by points: if/else 11 (29 pts), ternaries 6 (24 pts), boolean chains 7, match/switch 1 (5 pts), loops 2 (nesting depth added 40). 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":"Wikipedia/Code/DiffTransformer.swift"},"region":{"startLine":99}}}],"partialFingerprints":{"codehealthFindingId/v1":"2659d10aab877b139dbb6ce1f469335210c4ce1514b1c618187cdffdfbdfe2a6"}},{"ruleId":"D2","level":"warning","message":{"text":"HtmlUtils.addStyling (cognitive 64): HtmlUtils.addStyling has cognitive complexity 64 (threshold 15). Drivers by points: if/else 17 (43 pts), loops 14 (19 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":"WMFComponents/Sources/WMFComponents/Utility/HTMLUtils.swift"},"region":{"startLine":320}}}],"partialFingerprints":{"codehealthFindingId/v1":"cce28b524e3c647c3a7dedeff3fcac97f838bd2ec9fa38f3014d67cd3cdd338b"}},{"ruleId":"D2","level":"warning","message":{"text":"DonateCoordinator.presentActionSheet (cognitive 61): DonateCoordinator.presentActionSheet has cognitive complexity 61 (threshold 15). Drivers by points: if/else 32 (52 pts), match/switch 7, boolean chains 1, ternaries 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":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":226}}}],"partialFingerprints":{"codehealthFindingId/v1":"fb7761fb9afa5dd1ccff8beead47ac4ec3afec4e82fc70d6ca9f1b4f79ec89ce"}},{"ruleId":"D2","level":"warning","message":{"text":"Router.destinationForWikiResourceURL (cognitive 59): Router.destinationForWikiResourceURL has cognitive complexity 59 (threshold 15). Drivers by points: if/else 20 (36 pts), boolean chains 18, ternaries 2 (4 pts), match/switch 1 (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":"WMF Framework/Router.swift"},"region":{"startLine":54}}}],"partialFingerprints":{"codehealthFindingId/v1":"79a88f781ab27074c9a3dd97b28a9fc031b4e91021a3ad9c772209b50608f9af"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFDatabaseHousekeeper.deleteStaleUnreferencedArticles (cognitive 59): WMFDatabaseHousekeeper.deleteStaleUnreferencedArticles has cognitive complexity 59 (threshold 15). Drivers by points: if/else 18 (41 pts), loops 4 (8 pts), boolean chains 5, match/switch 1 (3 pts), ternaries 2 (nesting depth added 29). 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":"Wikipedia/Code/WMFDatabaseHousekeeper.swift"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"1f0ef107387bdd4957c6de7ffabcb298f3fe816d2f5226fcbbe523b705193ba2"}},{"ruleId":"D2","level":"warning","message":{"text":"TimelineViewModel.fetch (cognitive 57): TimelineViewModel.fetch has cognitive complexity 57 (threshold 15). Drivers by points: if/else 14 (41 pts), loops 2 (9 pts), boolean chains 6, error handling 1 (nesting depth added 34). 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":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/TimelineViewModel.swift"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"95b39eeb76cca240ec4bcea01166e89ef15c05a8a9b82b5556d9a1345ca35af6"}},{"ruleId":"D2","level":"warning","message":{"text":"ReadingListsSyncOperation.locallyCreate (cognitive 57): ReadingListsSyncOperation.locallyCreate has cognitive complexity 57 (threshold 15). Drivers by points: if/else 23 (46 pts), loops 5 (7 pts), boolean chains 4 (nesting depth added 25). 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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":756}}}],"partialFingerprints":{"codehealthFindingId/v1":"4b8fdb6f27e84f336afed719b41835d28d312363c6beb870c66376bda6445e13"}},{"ruleId":"D2","level":"warning","message":{"text":"PlacesViewController.adjustLayout (cognitive 57): PlacesViewController.adjustLayout has cognitive complexity 57 (threshold 15). Drivers by points: if/else 24 (32 pts), boolean chains 16, ternaries 4 (8 pts), loops 1 (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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":1829}}}],"partialFingerprints":{"codehealthFindingId/v1":"a0af0bf0d07f6f9b72fdbd7b200db7f7d716ed1bb04d132f8470ab4ca93ff498"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFUserImpactDataController.fetch (cognitive 56): WMFUserImpactDataController.fetch has cognitive complexity 56 (threshold 15). Drivers by points: if/else 15 (40 pts), loops 4 (13 pts), boolean chains 2, match/switch 1 (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":"WMFData/Sources/WMFData/Data Controllers/Shared/WMFUserImpactDataController.swift"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"d4a5dd70723bd282744a875a85fc58051d765741a642665570645ecb86783d69"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticleCacheDBWriter.syncResources (cognitive 56): ArticleCacheDBWriter.syncResources has cognitive complexity 56 (threshold 15). Drivers by points: if/else 19 (40 pts), boolean chains 6, loops 3 (6 pts), match/switch 2 (3 pts), error handling 1 (nesting depth added 25). 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":"Wikipedia/Code/ArticleCacheDBWriter.swift"},"region":{"startLine":35}}}],"partialFingerprints":{"codehealthFindingId/v1":"9921bd55e392d7fc6abde47771595a0254dd2295f6c4f15c4e742cdffb4c802e"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFDailyGameExploreCell.sizeThatFits (cognitive 55): WMFDailyGameExploreCell.sizeThatFits has cognitive complexity 55 (threshold 15). Drivers by points: if/else 28 (52 pts), ternaries 1 (3 pts) (nesting depth added 26). 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":"Wikipedia/Code/WMFDailyGameExploreCell.swift"},"region":{"startLine":226}}}],"partialFingerprints":{"codehealthFindingId/v1":"849deceaa8d93ed7a87ecef9d1d30799e4f2db68234acf08631223a363499d2b"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFArticleSavedStateMigrationManager.migrateSyncedArticles (cognitive 51): WMFArticleSavedStateMigrationManager.migrateSyncedArticles has cognitive complexity 51 (threshold 15). Drivers by points: if/else 14 (37 pts), loops 3 (8 pts), error handling 3 (5 pts), boolean chains 1 (nesting depth added 30). 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":"WMF Framework/WMFArticle\u002BMigration.swift"},"region":{"startLine":201}}}],"partialFingerprints":{"codehealthFindingId/v1":"7f7910eef457bbd88d02d953fdee135fbab3c151ff40d4d26774b022b0f18e3a"}},{"ruleId":"D2","level":"warning","message":{"text":"String.pluralDictionary (cognitive 50): String.pluralDictionary has cognitive complexity 50 (threshold 15). Drivers by points: if/else 16 (36 pts), loops 3 (6 pts), boolean chains 5, ternaries 1 (3 pts) (nesting depth added 25). 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":"WMF Framework/HasText.swift"},"region":{"startLine":83}}}],"partialFingerprints":{"codehealthFindingId/v1":"b5aec36889878018d4992b373509147ae51509c54b33151720bce0b546024929"}},{"ruleId":"D2","level":"warning","message":{"text":"DiffContainerViewController.setupDiffListViewControllerIfNeeded (cognitive 47): DiffContainerViewController.setupDiffListViewControllerIfNeeded has cognitive complexity 47 (threshold 15). Drivers by points: if/else 18 (40 pts), match/switch 2 (4 pts), boolean chains 3 (nesting depth added 24). 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":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":882}}}],"partialFingerprints":{"codehealthFindingId/v1":"ea302a56c9efcfc80d53a3f8ef637041c09f3133fc1554c98919caef8a82ebfc"}},{"ruleId":"D2","level":"warning","message":{"text":"ReadingListsCollectionViewCell.sizeThatFits (cognitive 45): ReadingListsCollectionViewCell.sizeThatFits has cognitive complexity 45 (threshold 15). Drivers by points: if/else 23 (32 pts), ternaries 4 (7 pts), boolean chains 6 (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":"Wikipedia/Code/ReadingListsCollectionViewCell.swift"},"region":{"startLine":114}}}],"partialFingerprints":{"codehealthFindingId/v1":"2aec024ca850d03813cff787f5224e48284bc50dba831a2b29b18b6cc549d482"}},{"ruleId":"D2","level":"warning","message":{"text":"localization.swift.importLocalizationsFromTWN (cognitive 45): localization.swift.importLocalizationsFromTWN has cognitive complexity 45 (threshold 15). Drivers by points: if/else 13 (33 pts), loops 4 (8 pts), boolean chains 3, error handling 1 (nesting depth added 24). 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":"Command Line Tools/Update Localizations/localization.swift"},"region":{"startLine":433}}}],"partialFingerprints":{"codehealthFindingId/v1":"ab4232e4ba63fd5e8e737d446a2aa4eb2bdaa66178163af2122b0999f3bd04ad"}},{"ruleId":"D2","level":"warning","message":{"text":"CollectionViewUpdater.controllerDidChangeContent (cognitive 44): CollectionViewUpdater.controllerDidChangeContent has cognitive complexity 44 (threshold 15). Drivers by points: if/else 15 (26 pts), boolean chains 10, loops 3 (4 pts), match/switch 2 (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":"Wikipedia/Code/CollectionViewUpdater.swift"},"region":{"startLine":69}}}],"partialFingerprints":{"codehealthFindingId/v1":"2f1abb6c35cf221cb1865064d03437990951c422e9608a72f18077914a916b6b"}},{"ruleId":"D2","level":"warning","message":{"text":"DescriptionEditViewController.save (cognitive 43): DescriptionEditViewController.save has cognitive complexity 43 (threshold 15). Drivers by points: if/else 17 (34 pts), match/switch 3 (6 pts), boolean chains 3 (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":"Wikipedia/Code/DescriptionEditViewController.swift"},"region":{"startLine":342}}}],"partialFingerprints":{"codehealthFindingId/v1":"3b972d583ef19fddfdda7044dc01a6519faa4d444aeac89c2187bdff996b867f"}},{"ruleId":"D2","level":"warning","message":{"text":"PlacesViewController.performSearch (cognitive 43): PlacesViewController.performSearch has cognitive complexity 43 (threshold 15). Drivers by points: if/else 17 (38 pts), boolean chains 2, error handling 1 (2 pts), match/switch 1 (nesting depth added 22). 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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":682}}}],"partialFingerprints":{"codehealthFindingId/v1":"8eda0941a4eb31dcbb16bd86e287caebff6a24fa472edea51eab6b1536f2318e"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFWatchlistFilterViewModel.generateDataForNewFilterSettings (cognitive 42): WMFWatchlistFilterViewModel.generateDataForNewFilterSettings has cognitive complexity 42 (threshold 15). Drivers by points: if/else 31 (33 pts), boolean chains 7, loops 2 (nesting depth added 2). 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":"WMFComponents/Sources/WMFComponents/Components/Watchlist/Filter/WMFWatchlistFilterViewModel.swift"},"region":{"startLine":140}}}],"partialFingerprints":{"codehealthFindingId/v1":"356de4f534ffe774e062c0fa2f526ba6d13d29bb5e5b81f4c0338c2fde6ffa0e"}},{"ruleId":"D2","level":"warning","message":{"text":"ReadingListsSyncOperation.executeSync (cognitive 42): ReadingListsSyncOperation.executeSync has cognitive complexity 42 (threshold 15). Drivers by points: if/else 27 (39 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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":60}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c08123b75c5d9e7333ff9f139ddb8cf16979e6c13a2f9a0b8058f59e3d28e5a"}},{"ruleId":"D2","level":"warning","message":{"text":"ReadingListsSyncOperation.createOrUpdate (cognitive 42): ReadingListsSyncOperation.createOrUpdate has cognitive complexity 42 (threshold 15). Drivers by points: if/else 17 (35 pts), loops 4 (5 pts), boolean chains 2 (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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":914}}}],"partialFingerprints":{"codehealthFindingId/v1":"c41361a91cc56514eaa838e8bca5a5e4618f60e3d55b0395884364e15446419f"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFNavigationBarConfiguring.configureNavigationBar (cognitive 41): WMFNavigationBarConfiguring.configureNavigationBar has cognitive complexity 41 (threshold 15). Drivers by points: if/else 17 (33 pts), boolean chains 5, match/switch 2 (3 pts) (nesting depth added 17). 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":"WMFComponents/Sources/WMFComponents/Extensions/Navigation Bar/WMFNavigationBarConfiguring.swift"},"region":{"startLine":119}}}],"partialFingerprints":{"codehealthFindingId/v1":"b1701972864330d8c6d8d762d62b130f5cf7bb5aeae1f4ad2fab315021b59e32"}},{"ruleId":"D2","level":"warning","message":{"text":"NotificationsCenterViewController.userDidPanCell (cognitive 41): NotificationsCenterViewController.userDidPanCell has cognitive complexity 41 (threshold 15). Drivers by points: if/else 16 (30 pts), ternaries 3 (7 pts), boolean chains 3, match/switch 1 (nesting depth added 18). 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":"Wikipedia/Code/NotificationsCenterViewController.swift"},"region":{"startLine":778}}}],"partialFingerprints":{"codehealthFindingId/v1":"dec0b5a2c9b2a07194a9767e529d2971141b02f7872218df066d923f2b2d782c"}},{"ruleId":"D2","level":"warning","message":{"text":"PageHistoryViewController.configure (cognitive 40): PageHistoryViewController.configure has cognitive complexity 40 (threshold 15). Drivers by points: if/else 17 (28 pts), ternaries 3 (10 pts), boolean chains 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":"Wikipedia/Code/PageHistoryViewController.swift"},"region":{"startLine":458}}}],"partialFingerprints":{"codehealthFindingId/v1":"ad03c831e86f383105598d86de96aa1666a8766a77bee179adcdea135a362d1d"}},{"ruleId":"D2","level":"warning","message":{"text":"DetailTransition.animateTransition (cognitive 39): DetailTransition.animateTransition has cognitive complexity 39 (threshold 15). Drivers by points: if/else 19 (21 pts), boolean chains 12, ternaries 4 (6 pts) (nesting depth added 4). 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":"Wikipedia/Code/DetailTransition.swift"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"fc3cf90a79134c169cd0982424fb6991d422a0f65a21b969484c53f5b2b025ec"}},{"ruleId":"D2","level":"warning","message":{"text":"DiffContainerViewController.completeRollbackOrUndo (cognitive 39): DiffContainerViewController.completeRollbackOrUndo has cognitive complexity 39 (threshold 15). Drivers by points: if/else 18 (31 pts), match/switch 3 (6 pts), ternaries 1 (2 pts) (nesting depth added 17). 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":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":1291}}}],"partialFingerprints":{"codehealthFindingId/v1":"bbc439211c00287946d55d7f1346331ce4eb108ac943bff8d1aaba90b74d27b6"}},{"ruleId":"D2","level":"warning","message":{"text":"Router.destinationForWResourceURL (cognitive 37): Router.destinationForWResourceURL has cognitive complexity 37 (threshold 15). Drivers by points: boolean chains 20, if/else 15 (16 pts), loops 1 (nesting depth added 1). 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":"WMF Framework/Router.swift"},"region":{"startLine":163}}}],"partialFingerprints":{"codehealthFindingId/v1":"6c9290255bf39b2effa16a9c76458d6530201941699878983ca88401ea8aac8a"}},{"ruleId":"D2","level":"warning","message":{"text":"PlacesViewController.merge (cognitive 37): PlacesViewController.merge has cognitive complexity 37 (threshold 15). Drivers by points: if/else 7 (22 pts), boolean chains 6, loops 2 (5 pts), ternaries 1 (4 pts) (nesting depth added 21). 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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":1402}}}],"partialFingerprints":{"codehealthFindingId/v1":"c06cded16228561b08c61a52f403d37f2568f9aaa7546f927493033c52c7f559"}},{"ruleId":"D2","level":"warning","message":{"text":"SavedAllArticlesCoordinator.fetchAllSavedArticles (cognitive 37): SavedAllArticlesCoordinator.fetchAllSavedArticles has cognitive complexity 37 (threshold 15). Drivers by points: if/else 10 (29 pts), boolean chains 3, loops 1 (2 pts), match/switch 1 (2 pts), error handling 1 (nesting depth added 21). 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":"Wikipedia/Code/SavedAllArticlesCoordinator.swift"},"region":{"startLine":435}}}],"partialFingerprints":{"codehealthFindingId/v1":"8a94aba67fb50cc29a132c3314b74684cef7acaf782eb8564a91ef6446ff4c5f"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticleCollectionViewCell.sizeThatFits (cognitive 36): ArticleCollectionViewCell.sizeThatFits has cognitive complexity 36 (threshold 15). Drivers by points: if/else 11 (20 pts), ternaries 5 (14 pts), boolean chains 2 (nesting depth added 18). 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":"Wikipedia/Code/ArticleCollectionViewCell.swift"},"region":{"startLine":154}}}],"partialFingerprints":{"codehealthFindingId/v1":"b59bc0996e89b2d54ee7763fe8a703098a1c02981c747bea47ddd67e4b0e787d"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticlePeekPreviewViewController.contextMenuItems (cognitive 36): ArticlePeekPreviewViewController.contextMenuItems has cognitive complexity 36 (threshold 15). Drivers by points: if/else 14 (22 pts), boolean chains 6, ternaries 3 (6 pts), error handling 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":"Wikipedia/Code/ArticlePeekPreviewViewController.swift"},"region":{"startLine":115}}}],"partialFingerprints":{"codehealthFindingId/v1":"58a1db31e50ab95e377c9d68e49397fb635c1e987c37b871ee1a3a053472dc9e"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFAppViewController.processUserActivity (cognitive 36): WMFAppViewController.processUserActivity has cognitive complexity 36 (threshold 15). Drivers by points: if/else 15 (29 pts), match/switch 2 (4 pts), boolean chains 3 (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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":1319}}}],"partialFingerprints":{"codehealthFindingId/v1":"967a41b7f5fa2ea63754599589f911522098f7fd85a0e823729b3a617672eed8"}},{"ruleId":"D2","level":"warning","message":{"text":"TalkPageFindInPageSearchController.search (cognitive 34): TalkPageFindInPageSearchController.search has cognitive complexity 34 (threshold 15). Drivers by points: loops 6 (18 pts), if/else 6 (14 pts), boolean chains 2 (nesting depth added 20). 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":"Wikipedia/Code/TalkPageFindInPageSearchController.swift"},"region":{"startLine":43}}}],"partialFingerprints":{"codehealthFindingId/v1":"54b5c0aa0f261d322bad460f59292f9b1ec92d46478c5b3b33b3fa0e92388cde"}},{"ruleId":"D2","level":"warning","message":{"text":"TalkPageViewController.tappedPublish (cognitive 34): TalkPageViewController.tappedPublish has cognitive complexity 34 (threshold 15). Drivers by points: if/else 14 (26 pts), boolean chains 5, match/switch 2 (3 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":"Wikipedia/Code/TalkPageViewController.swift"},"region":{"startLine":1136}}}],"partialFingerprints":{"codehealthFindingId/v1":"ab35aa5bdd7b72f2f5b88402971a751df91019ee7536e9d12b2d02ade4fe9c35"}},{"ruleId":"D2","level":"warning","message":{"text":"HtmlUtils.addStyling (cognitive 33): HtmlUtils.addStyling has cognitive complexity 33 (threshold 15). Drivers by points: loops 14 (19 pts), if/else 6 (14 pts) (nesting depth added 13). 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":"WMFComponents/Sources/WMFComponents/Utility/HTMLUtils.swift"},"region":{"startLine":168}}}],"partialFingerprints":{"codehealthFindingId/v1":"53ddd96d4755a95ac816de69a3d6bbf2d59994b59e7a01670a8ef2882c70bc3b"}},{"ruleId":"D2","level":"warning","message":{"text":"PageHistoryCollectionViewCell.sizeThatFits (cognitive 33): PageHistoryCollectionViewCell.sizeThatFits has cognitive complexity 33 (threshold 15). Drivers by points: if/else 15 (17 pts), ternaries 8 (15 pts), boolean chains 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":"Wikipedia/Code/PageHistoryCollectionViewCell.swift"},"region":{"startLine":173}}}],"partialFingerprints":{"codehealthFindingId/v1":"54e39a31851dea494abfc0ae2d11a41d58ec5a92c648deb9b0aeb64a304a5b2e"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFAppViewControllerTipWrapper.listenForTooltips (cognitive 32): WMFAppViewControllerTipWrapper.listenForTooltips has cognitive complexity 32 (threshold 15). Drivers by points: if/else 12 (23 pts), boolean chains 5, ternaries 1 (3 pts), loops 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":"Wikipedia/Code/AppViewControllerTipWrapper.swift"},"region":{"startLine":28}}}],"partialFingerprints":{"codehealthFindingId/v1":"748c397203e8051c65aeb8c9245e3bfcca6ce17c2afa8e3ec68b6dbfe29a43f7"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFAuthenticationManager.loginWithSavedCredentials (cognitive 32): WMFAuthenticationManager.loginWithSavedCredentials has cognitive complexity 32 (threshold 15). Drivers by points: if/else 14 (25 pts), match/switch 2 (4 pts), boolean chains 3 (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":"Wikipedia/Code/WMFAuthenticationManager.swift"},"region":{"startLine":253}}}],"partialFingerprints":{"codehealthFindingId/v1":"82477258700888b4992723911e781a0bb7ee3a3adf33abffbe824471c35cf6e1"}},{"ruleId":"D2","level":"warning","message":{"text":"HtmlUtils.listInsertData (cognitive 31): HtmlUtils.listInsertData has cognitive complexity 31 (threshold 15). Drivers by points: if/else 14 (25 pts), boolean chains 4, match/switch 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":"WMFComponents/Sources/WMFComponents/Utility/HTMLUtils.swift"},"region":{"startLine":518}}}],"partialFingerprints":{"codehealthFindingId/v1":"d5e8645fe867cb21ae6a9ae636091784afb71120f437000eadf71a6f990b37ff"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFActivityTabView.loggedInList (cognitive 31): WMFActivityTabView.loggedInList has cognitive complexity 31 (threshold 15). Drivers by points: if/else 14 (26 pts), boolean chains 5 (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":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift"},"region":{"startLine":80}}}],"partialFingerprints":{"codehealthFindingId/v1":"74554b03ab318b58e5ec0a4bc7e1c8ac6c5abf84f634c2e2d8118b1a0ba52035"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFBasicService.performPOST (cognitive 31): WMFBasicService.performPOST has cognitive complexity 31 (threshold 15). Drivers by points: if/else 10 (20 pts), loops 1 (4 pts), error handling 1 (3 pts), boolean chains 2, match/switch 1 (2 pts) (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":"WMFData/Sources/WMFData/Service/WMFBasicService.swift"},"region":{"startLine":59}}}],"partialFingerprints":{"codehealthFindingId/v1":"2f5ea7ec54804ee7040aacf6e5cd65b22c80257b8eb88017bc1262a5a66907a2"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFWikitextUtils.insertImageWikitextIntoArticleWikitextAfterTemplates (cognitive 31): WMFWikitextUtils.insertImageWikitextIntoArticleWikitextAfterTemplates has cognitive complexity 31 (threshold 15). Drivers by points: if/else 13 (27 pts), loops 3 (4 pts) (nesting depth added 15). 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":"WMFData/Sources/WMFData/Utility/WMFWikitextUtils.swift"},"region":{"startLine":150}}}],"partialFingerprints":{"codehealthFindingId/v1":"6a7f2d5db62c81083238a7915add2ccb9c2562ed96692c102e225f348c061533"}},{"ruleId":"D2","level":"warning","message":{"text":"ActionsView.sizeThatFits (cognitive 31): ActionsView.sizeThatFits has cognitive complexity 31 (threshold 15). Drivers by points: if/else 8 (16 pts), ternaries 4 (8 pts), loops 2 (6 pts), boolean chains 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":"WMF Framework/CollectionViewCellActionsView.swift"},"region":{"startLine":89}}}],"partialFingerprints":{"codehealthFindingId/v1":"c606afeabbf0491598b91983121f7a2cb6d208cf29c84e9c071cc33d3ca5443e"}},{"ruleId":"D2","level":"warning","message":{"text":"SavedArticlesCollectionViewCell.sizeThatFits (cognitive 31): SavedArticlesCollectionViewCell.sizeThatFits has cognitive complexity 31 (threshold 15). Drivers by points: if/else 16 (19 pts), ternaries 4 (8 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":"Wikipedia/Code/SavedArticlesCollectionViewCell.swift"},"region":{"startLine":134}}}],"partialFingerprints":{"codehealthFindingId/v1":"6bf007c4f2ef56da7a13f28e7394493140b9e06e01d4bf1e16d4802679902b2c"}},{"ruleId":"D2","level":"warning","message":{"text":"TalkPageViewController.tappedPublish (cognitive 31): TalkPageViewController.tappedPublish has cognitive complexity 31 (threshold 15). Drivers by points: if/else 13 (23 pts), boolean chains 5, match/switch 2 (3 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":"Wikipedia/Code/TalkPageViewController.swift"},"region":{"startLine":1231}}}],"partialFingerprints":{"codehealthFindingId/v1":"bdb96426dfb2e56130a176a47049784e430567245ef25eab2bfb06de8ba501a3"}},{"ruleId":"D2","level":"warning","message":{"text":"ReadingListsSyncOperation.executeRandomArticlePopulation (cognitive 30): ReadingListsSyncOperation.executeRandomArticlePopulation has cognitive complexity 30 (threshold 15). Drivers by points: if/else 8 (25 pts), boolean chains 2, loops 1 (2 pts), error handling 1 (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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":379}}}],"partialFingerprints":{"codehealthFindingId/v1":"90b8684adf951f63164e280b16c3919c14739986d8f5a282425bef0bb9384b7e"}},{"ruleId":"D2","level":"warning","message":{"text":"ReadingListsSyncOperation.createOrUpdate (cognitive 30): ReadingListsSyncOperation.createOrUpdate has cognitive complexity 30 (threshold 15). Drivers by points: if/else 9 (20 pts), loops 5 (8 pts), boolean chains 2 (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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":1010}}}],"partialFingerprints":{"codehealthFindingId/v1":"d1a88718d0b4aca04dabcee49652fb5a96a6a5d4bbc170c6d737f7a1f870e4c1"}},{"ruleId":"D2","level":"warning","message":{"text":"WidgetController.fetchTopReadContent (cognitive 30): WidgetController.fetchTopReadContent has cognitive complexity 30 (threshold 15). Drivers by points: if/else 11 (19 pts), match/switch 2 (5 pts), loops 1 (3 pts), boolean chains 2, ternaries 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":"WMF Framework/Widget/WidgetController.swift"},"region":{"startLine":370}}}],"partialFingerprints":{"codehealthFindingId/v1":"2ff0607c64f2f8438403698f2b192627d1541c33bf7cad7fcdcde80ba11a5582"}},{"ruleId":"D2","level":"warning","message":{"text":"DiffListChangeItemViewModel.calculateAttributedString (cognitive 30): DiffListChangeItemViewModel.calculateAttributedString has cognitive complexity 30 (threshold 15). Drivers by points: if/else 9 (12 pts), ternaries 3 (7 pts), boolean chains 5, match/switch 3 (5 pts), loops 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":"Wikipedia/Code/DiffListChangeItemViewModel.swift"},"region":{"startLine":302}}}],"partialFingerprints":{"codehealthFindingId/v1":"f1871d1ba76e622ce0118c61630e467ec576a930a6ad513612aa9253e2e20321"}},{"ruleId":"D2","level":"warning","message":{"text":"PlacesViewController.updatePlaces (cognitive 30): PlacesViewController.updatePlaces has cognitive complexity 30 (threshold 15). Drivers by points: if/else 9 (18 pts), boolean chains 8, 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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":843}}}],"partialFingerprints":{"codehealthFindingId/v1":"69ee9547d8dba430f88db4a25ec806549dcf3c37b98bab216e953cf1c39aaaac"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticleCacheController.syncCachedResources (cognitive 29): ArticleCacheController.syncCachedResources has cognitive complexity 29 (threshold 15). Drivers by points: match/switch 5 (15 pts), if/else 4 (9 pts), loops 2 (4 pts), boolean chains 1 (nesting depth added 17). 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":"WMF Framework/ArticleCacheController.swift"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"55d85cda2e3fb4abf6b5e5bd7fd70d86c425eba24789aa93ecc3ddb7028198cf"}},{"ruleId":"D2","level":"warning","message":{"text":"NotificationsCenterDetailViewModel.primaryAction (cognitive 29): NotificationsCenterDetailViewModel.primaryAction has cognitive complexity 29 (threshold 15). Drivers by points: if/else 13 (26 pts), boolean chains 2, match/switch 1 (nesting depth added 13). 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":"Wikipedia/Code/NotificationsCenterDetailViewModel.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"2b692f6168093c656a4de480258116bcb2ed2f629f25eaccd9f94c4af804b9e2"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFWatchlistDataController.fetchWatchlist (cognitive 28): WMFWatchlistDataController.fetchWatchlist has cognitive complexity 28 (threshold 15). Drivers by points: if/else 11 (24 pts), match/switch 1 (2 pts), boolean chains 1, loops 1 (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":"WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"8d6b9cef8fb51f550ef160a3ed3b1938cc5f62cc3bdd1e429e42c7147d4e85b8"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFArticleTabsDataController.appendArticle (cognitive 27): WMFArticleTabsDataController.appendArticle has cognitive complexity 27 (threshold 15). Drivers by points: if/else 13 (22 pts), boolean chains 3, loops 1 (2 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":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":340}}}],"partialFingerprints":{"codehealthFindingId/v1":"8966c212d97cf360b5f7140a89397d88e2bd5d3c7bab4ffd4b3761f6e91df22f"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFArticleTabsDataController.fetchAllArticleTabs (cognitive 27): WMFArticleTabsDataController.fetchAllArticleTabs has cognitive complexity 27 (threshold 15). Drivers by points: if/else 9 (18 pts), boolean chains 6, loops 2 (3 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":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":768}}}],"partialFingerprints":{"codehealthFindingId/v1":"d6c8e436b695a5fc6307f24dad094c6214224c004db911165d0c084dc8dc0648"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFExperimentsDataController.determineBucketForExperiment (cognitive 27): WMFExperimentsDataController.determineBucketForExperiment has cognitive complexity 27 (threshold 15). Drivers by points: if/else 13 (21 pts), boolean chains 4, match/switch 1 (2 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":"WMFData/Sources/WMFData/Data Controllers/Experiments/WMFExperimentsDataController.swift"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"6ed00ca187c80f8ffc76f1aceeb864a97218db4e7c1451b217819709ef4bcec3"}},{"ruleId":"D2","level":"warning","message":{"text":"CacheController.finishDBAdd (cognitive 27): CacheController.finishDBAdd has cognitive complexity 27 (threshold 15). Drivers by points: if/else 6 (16 pts), match/switch 3 (8 pts), loops 1 (2 pts), boolean chains 1 (nesting depth added 16). 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":"WMF Framework/CacheController.swift"},"region":{"startLine":186}}}],"partialFingerprints":{"codehealthFindingId/v1":"42faae5946d7d8840dd178d8ce256f86f5a94655ce8f1c455df2691fade42839"}},{"ruleId":"D2","level":"warning","message":{"text":"ExploreCardCollectionViewCell.sizeThatFits (cognitive 27): ExploreCardCollectionViewCell.sizeThatFits has cognitive complexity 27 (threshold 15). Drivers by points: if/else 12 (15 pts), ternaries 5 (9 pts), boolean chains 3 (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":"WMF Framework/ExploreCardCollectionViewCell.swift"},"region":{"startLine":204}}}],"partialFingerprints":{"codehealthFindingId/v1":"a3393827dcc9b42594da8cd0ba6d4d3733bdc91e3ba5191dc1819683f9a2d16e"}},{"ruleId":"D2","level":"warning","message":{"text":"MediaWikiFetcher.perform (cognitive 27): MediaWikiFetcher.perform has cognitive complexity 27 (threshold 15). Drivers by points: if/else 12 (20 pts), match/switch 2 (4 pts), boolean chains 3 (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":"WMF Framework/MediaWikiFetcher.swift"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"74a6b1c011d3a12ca765f26945588d13c6641c541675fc5dd5aaa1967c614f3d"}},{"ruleId":"D2","level":"warning","message":{"text":"DiffTransformer.transformSectionInfosOfItems (cognitive 27): DiffTransformer.transformSectionInfosOfItems has cognitive complexity 27 (threshold 15). Drivers by points: if/else 6 (16 pts), loops 3 (7 pts), boolean chains 4 (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":"Wikipedia/Code/DiffTransformer.swift"},"region":{"startLine":182}}}],"partialFingerprints":{"codehealthFindingId/v1":"b0385aeffdec097d4bb540ff54ce7583089cdbfde6a94edacd3404444427e117"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFArticleTabsDataController.getAdjacentArticleInTab (cognitive 26): WMFArticleTabsDataController.getAdjacentArticleInTab has cognitive complexity 26 (threshold 15). Drivers by points: if/else 10 (15 pts), boolean chains 10, loops 1 (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":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":422}}}],"partialFingerprints":{"codehealthFindingId/v1":"c054cfdccace630abaa9e87039934586ce2cda65d8e8ecbd7293ba0e88980ce3"}},{"ruleId":"D2","level":"warning","message":{"text":"CollectionViewUpdater.performBatchUpdates (cognitive 26): CollectionViewUpdater.performBatchUpdates has cognitive complexity 26 (threshold 15). Drivers by points: if/else 11 (19 pts), match/switch 2 (4 pts), loops 2, boolean chains 1 (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":"Wikipedia/Code/CollectionViewUpdater.swift"},"region":{"startLine":178}}}],"partialFingerprints":{"codehealthFindingId/v1":"25317f5c6935eafde7787f2fc9d39da126772406bc62678e8ff03680d0867c24"}},{"ruleId":"D2","level":"warning","message":{"text":"SavedArticlesFetcher._update (cognitive 26): SavedArticlesFetcher._update has cognitive complexity 26 (threshold 15). Drivers by points: match/switch 4 (10 pts), if/else 6 (9 pts), boolean chains 4, error handling 2 (3 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":"Wikipedia/Code/SavedArticlesFetcher.swift"},"region":{"startLine":164}}}],"partialFingerprints":{"codehealthFindingId/v1":"97d9d41bcc3c68045390f2015026c4eac7d53cf88d1ccdcaebb8245af90fc0c5"}},{"ruleId":"D2","level":"warning","message":{"text":"Session.request (cognitive 26): Session.request has cognitive complexity 26 (threshold 15). Drivers by points: if/else 13 (18 pts), error handling 1 (3 pts), boolean chains 2, loops 2, match/switch 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":"Wikipedia/Code/Session.swift"},"region":{"startLine":230}}}],"partialFingerprints":{"codehealthFindingId/v1":"73c2118c7945b7b6470efefc66926bef3f0efa263738e92ee3e7161c0056f284"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFForYouArticleCardView.body (cognitive 25): WMFForYouArticleCardView.body has cognitive complexity 25 (threshold 15). Drivers by points: if/else 10 (14 pts), ternaries 4 (7 pts), match/switch 3 (4 pts) (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":"WMFComponents/Sources/WMFComponents/Components/Home/WMFForYouView.swift"},"region":{"startLine":879}}}],"partialFingerprints":{"codehealthFindingId/v1":"d2cbb00107a596ea981764735ec296ea1239f4b838401e6646807684b1f923e5"}},{"ruleId":"D2","level":"warning","message":{"text":"ColumnarCollectionViewLayout.prepare (cognitive 25): ColumnarCollectionViewLayout.prepare has cognitive complexity 25 (threshold 15). Drivers by points: if/else 8 (15 pts), boolean chains 6, 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":"WMF Framework/ColumnarCollectionViewLayout.swift"},"region":{"startLine":190}}}],"partialFingerprints":{"codehealthFindingId/v1":"bd80b03153cf5d39743e7b8b13198457f88672d422a3a825c2ecb69fc6ddc6a7"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFArticleSavedStateMigrationManager.runMigration (cognitive 25): WMFArticleSavedStateMigrationManager.runMigration has cognitive complexity 25 (threshold 15). Drivers by points: if/else 8 (14 pts), error handling 3 (5 pts), loops 2 (4 pts), boolean chains 2 (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":"WMF Framework/WMFArticle\u002BMigration.swift"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"bf7cbf1cd465280bf94ac828c06976e095265a710072f80d3a326546fdebfe9e"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticleTabCoordinating.trackArticleTab (cognitive 25): ArticleTabCoordinating.trackArticleTab has cognitive complexity 25 (threshold 15). Drivers by points: if/else 7 (14 pts), match/switch 3 (7 pts), boolean chains 3, error handling 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":"Wikipedia/Code/ArticleCoordinator.swift"},"region":{"startLine":32}}}],"partialFingerprints":{"codehealthFindingId/v1":"7aac9793e18004f79ed1be80345cdee29da9df8372c9c0ca0f4c5584bd60f9ce"}},{"ruleId":"D2","level":"warning","message":{"text":"EditSaveViewController.handleEditFailure (cognitive 25): EditSaveViewController.handleEditFailure has cognitive complexity 25 (threshold 15). Drivers by points: if/else 11 (19 pts), boolean chains 5, match/switch 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":"Wikipedia/Code/EditSaveViewController.swift"},"region":{"startLine":574}}}],"partialFingerprints":{"codehealthFindingId/v1":"31d935d54fd457ed43977f02d043d76695e5212a2f8671a81db187a7ac940814"}},{"ruleId":"D2","level":"warning","message":{"text":"ExploreViewController.collectionView (cognitive 25): ExploreViewController.collectionView has cognitive complexity 25 (threshold 15). Drivers by points: if/else 11 (16 pts), boolean chains 6, ternaries 1 (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":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":613}}}],"partialFingerprints":{"codehealthFindingId/v1":"5b6c9fd7b0ff5cb3c10c6e62bd8bb5bcfedca1944666ed5279ce66e6c811225c"}},{"ruleId":"D2","level":"warning","message":{"text":"HomeCoordinator.makeHomeViewController (cognitive 25): HomeCoordinator.makeHomeViewController has cognitive complexity 25 (threshold 15). Drivers by points: if/else 13, boolean chains 12. 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":"Wikipedia/Code/HomeCoordinator.swift"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"42af405452a7adb886ad2a5854089df458f9a5d6fc061e8a8312af7c041ade66"}},{"ruleId":"D2","level":"warning","message":{"text":"PageHistoryViewController.collectionView (cognitive 25): PageHistoryViewController.collectionView has cognitive complexity 25 (threshold 15). Drivers by points: if/else 9 (19 pts), boolean chains 6 (nesting depth added 10). 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":"Wikipedia/Code/PageHistoryViewController.swift"},"region":{"startLine":702}}}],"partialFingerprints":{"codehealthFindingId/v1":"a7df3a953df383822727a157c0f6c23cd8a3a473fa2b029767b8e80b4ea441d8"}},{"ruleId":"D2","level":"warning","message":{"text":"ViewControllerRouter.route (cognitive 25): ViewControllerRouter.route has cognitive complexity 25 (threshold 15). Drivers by points: if/else 11 (20 pts), boolean chains 4, match/switch 1 (nesting depth added 9). 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":"Wikipedia/Code/ViewControllerRouter.swift"},"region":{"startLine":89}}}],"partialFingerprints":{"codehealthFindingId/v1":"f67ee3203c9776ecd554c38b66252924dded880eebea0315bba13293d52d6a36"}},{"ruleId":"D2","level":"warning","message":{"text":"CacheController.remove (cognitive 24): CacheController.remove has cognitive complexity 24 (threshold 15). Drivers by points: if/else 7 (12 pts), match/switch 4 (10 pts), 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":"WMF Framework/CacheController.swift"},"region":{"startLine":290}}}],"partialFingerprints":{"codehealthFindingId/v1":"2ed8f555dea09cd2e5be1b00d3b1525a4f399eb943b4945e5ce84e8cd97c98d7"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticleRightAlignedImageCollectionViewCell.sizeThatFits (cognitive 24): ArticleRightAlignedImageCollectionViewCell.sizeThatFits has cognitive complexity 24 (threshold 15). Drivers by points: if/else 9 (10 pts), ternaries 5 (10 pts), boolean chains 4 (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":"Wikipedia/Code/ArticleRightAlignedImageCollectionViewCell.swift"},"region":{"startLine":41}}}],"partialFingerprints":{"codehealthFindingId/v1":"645c177b99b9b8123467264c21f7bc44f0beb777e3cb6f82954e74fdc094eb75"}},{"ruleId":"D2","level":"warning","message":{"text":"DiffListChangeItemViewModel.moveAttributedString (cognitive 24): DiffListChangeItemViewModel.moveAttributedString has cognitive complexity 24 (threshold 15). Drivers by points: match/switch 3 (10 pts), if/else 5 (7 pts), loops 1 (3 pts), boolean chains 2, ternaries 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":"Wikipedia/Code/DiffListChangeItemViewModel.swift"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"e045a67bb32c057b559d26ed15ff211a228e6ae7ab10e2aab092011e4b61bfb4"}},{"ruleId":"D2","level":"warning","message":{"text":"PageHistoryCollectionViewCell.apply (cognitive 24): PageHistoryCollectionViewCell.apply has cognitive complexity 24 (threshold 15). Drivers by points: if/else 14 (22 pts), ternaries 1 (2 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":"Wikipedia/Code/PageHistoryCollectionViewCell.swift"},"region":{"startLine":270}}}],"partialFingerprints":{"codehealthFindingId/v1":"84c406c7ff984db670ea122ea68174c4d01633277cfc6a376d7a9a014294c8c0"}},{"ruleId":"D2","level":"warning","message":{"text":"PageHistoryFetcher.fetchEditCounts (cognitive 24): PageHistoryFetcher.fetchEditCounts has cognitive complexity 24 (threshold 15). Drivers by points: if/else 8 (13 pts), boolean chains 10, loops 1 (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":"Wikipedia/Code/PageHistoryFetcher.swift"},"region":{"startLine":155}}}],"partialFingerprints":{"codehealthFindingId/v1":"8dc1d4680a34b1b23fd27edcdce62179fff7b7bad0d3726458dd8e3254b5fdb6"}},{"ruleId":"D2","level":"warning","message":{"text":"SchemeHandler.kickOffDataTask (cognitive 24): SchemeHandler.kickOffDataTask has cognitive complexity 24 (threshold 15). Drivers by points: if/else 20 (23 pts), boolean chains 1 (nesting depth added 3). 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":"Wikipedia/Code/SchemeHandler/SchemeHandler.swift"},"region":{"startLine":163}}}],"partialFingerprints":{"codehealthFindingId/v1":"34efc776259ff206822777ac81a673b00a4e1bb172d5f828cd00fb1157b17ea2"}},{"ruleId":"D2","level":"warning","message":{"text":"GenerateTopicsStrings.swift.injectIntoStringsFile (cognitive 24): GenerateTopicsStrings.swift.injectIntoStringsFile has cognitive complexity 24 (threshold 15). Drivers by points: if/else 14 (19 pts), loops 2, ternaries 1 (2 pts), boolean chains 1 (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":"scripts/GenerateTopicsStrings.swift"},"region":{"startLine":291}}}],"partialFingerprints":{"codehealthFindingId/v1":"e3f06fa64c254e08b6b6ff86f7e9f954b1da3cb0aff5d82dc545f31f454d8874"}},{"ruleId":"D2","level":"warning","message":{"text":"localization.swift.exportLocalizationsFromSourceCode (cognitive 24): localization.swift.exportLocalizationsFromSourceCode has cognitive complexity 24 (threshold 15). Drivers by points: if/else 6 (15 pts), loops 3 (6 pts), boolean chains 2, error handling 1 (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":"Command Line Tools/Update Localizations/localization.swift"},"region":{"startLine":341}}}],"partialFingerprints":{"codehealthFindingId/v1":"fa8c6eb4c6f3e529c1ce059077697c7efe20d25a64b52cb9f65c937237e4344a"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFEditorInputView.didSelectIndex (cognitive 23): WMFEditorInputView.didSelectIndex has cognitive complexity 23 (threshold 15). Drivers by points: match/switch 8 (15 pts), if/else 8 (nesting depth added 7). 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":"WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/Input Views/WMFEditorInputView.swift"},"region":{"startLine":419}}}],"partialFingerprints":{"codehealthFindingId/v1":"fd0fdde04836eaba05a19bcbe8633ded1af2a332abd4ca8ab7980ee35ff877a3"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFArticleDataController.fetchArticleInfo (cognitive 23): WMFArticleDataController.fetchArticleInfo has cognitive complexity 23 (threshold 15). Drivers by points: if/else 12 (17 pts), loops 1 (3 pts), boolean chains 2, match/switch 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":"WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleDataController.swift"},"region":{"startLine":102}}}],"partialFingerprints":{"codehealthFindingId/v1":"011391d63bdc23bf062808b7c56adfa5e380caaa0886c35097a2aa2e29d28f4d"}},{"ruleId":"D2","level":"warning","message":{"text":"WidgetController.fetchPictureOfTheDayContent (cognitive 23): WidgetController.fetchPictureOfTheDayContent has cognitive complexity 23 (threshold 15). Drivers by points: if/else 10 (18 pts), boolean chains 4, match/switch 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":"WMF Framework/Widget/WidgetController.swift"},"region":{"startLine":553}}}],"partialFingerprints":{"codehealthFindingId/v1":"e936a29e76bca73fee649c3b0f54af7f252208ef581a8000e70a16e1fb596340"}},{"ruleId":"D2","level":"warning","message":{"text":"DiffListViewController.didTapItem (cognitive 23): DiffListViewController.didTapItem has cognitive complexity 23 (threshold 15). Drivers by points: if/else 6 (11 pts), ternaries 2 (6 pts), loops 2 (4 pts), boolean chains 2 (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":"Wikipedia/Code/DiffListViewController.swift"},"region":{"startLine":383}}}],"partialFingerprints":{"codehealthFindingId/v1":"d4fafe2ff0a5aa7e950dd3b9e02d7d4deba6d4e87a4514cd9fbc0cfc6e8b0555"}},{"ruleId":"D2","level":"warning","message":{"text":"NotificationsCenterViewController.userDidTapMoreActionForCell (cognitive 23): NotificationsCenterViewController.userDidTapMoreActionForCell has cognitive complexity 23 (threshold 15). Drivers by points: if/else 12 (20 pts), boolean chains 2, match/switch 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":"Wikipedia/Code/NotificationsCenterViewController.swift"},"region":{"startLine":870}}}],"partialFingerprints":{"codehealthFindingId/v1":"5aae0f380cc96634f2918eafbe52e4a027f67a2555313b82362480c677fe8d92"}},{"ruleId":"D2","level":"warning","message":{"text":"PlacesViewController.updateSearchSuggestions (cognitive 23): PlacesViewController.updateSearchSuggestions has cognitive complexity 23 (threshold 15). Drivers by points: if/else 7 (12 pts), loops 1 (4 pts), match/switch 2 (3 pts), boolean chains 2, error handling 1 (2 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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":1981}}}],"partialFingerprints":{"codehealthFindingId/v1":"63f5543b7cbc46cfcf6fc2d8440f070295145290d204bafdf5d650f503a847f9"}},{"ruleId":"D2","level":"warning","message":{"text":"SavedArticlesFetcher.handleFailure (cognitive 23): SavedArticlesFetcher.handleFailure has cognitive complexity 23 (threshold 15). Drivers by points: if/else 12 (13 pts), match/switch 4 (8 pts), boolean chains 2 (nesting depth added 5). 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":"Wikipedia/Code/SavedArticlesFetcher.swift"},"region":{"startLine":308}}}],"partialFingerprints":{"codehealthFindingId/v1":"83fe8eadcb2c022b3481767e8249c383d192bec240659fc947625b3fa1d57563"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFDailyGameContentSource.loadNewContent (cognitive 23): WMFDailyGameContentSource.loadNewContent has cognitive complexity 23 (threshold 15). Drivers by points: if/else 8 (16 pts), ternaries 1 (4 pts), boolean chains 2, error handling 1 (nesting depth added 11). 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":"Wikipedia/Code/WMFDailyGameContentSource.swift"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"78ae140ee1fabc208b66111f94b1452e4e558b179bd7cc827a17ec7d0bda8593"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFContentGroup.imageURLsCompatibleWithTraitCollection (cognitive 23): WMFContentGroup.imageURLsCompatibleWithTraitCollection has cognitive complexity 23 (threshold 15). Drivers by points: if/else 9 (20 pts), loops 1 (2 pts), match/switch 1 (nesting depth added 12). 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":"WMF Framework/WMFContentGroup\u002BDisplay.swift"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"571d7ec4f8a8908955c2282be9457600844e93f64de2ca15880dc572db00c6bc"}},{"ruleId":"D2","level":"warning","message":{"text":"CollectionViewEditController.handlePanGesture (cognitive 22): CollectionViewEditController.handlePanGesture has cognitive complexity 22 (threshold 15). Drivers by points: if/else 8 (12 pts), ternaries 3 (7 pts), boolean chains 2, match/switch 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":"WMF Framework/CollectionViewEditController.swift"},"region":{"startLine":264}}}],"partialFingerprints":{"codehealthFindingId/v1":"0f55d568fe6f174aab15d9065199a27f72f0b5747de0400f7a3dafcf8b016d86"}},{"ruleId":"D2","level":"warning","message":{"text":"ReadingList.updateArticlesAndEntries (cognitive 22): ReadingList.updateArticlesAndEntries has cognitive complexity 22 (threshold 15). Drivers by points: if/else 8 (15 pts), loops 3 (5 pts), boolean chains 2 (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":"WMF Framework/ReadingList\u002BCoreDataClass.swift"},"region":{"startLine":34}}}],"partialFingerprints":{"codehealthFindingId/v1":"e456dd2930c315d6e21598201c2ce6645f518754e740d3945ea59178e6fa6dfa"}},{"ruleId":"D2","level":"warning","message":{"text":"WikipediaLanguageCommandLineUtility.getSiteInfoLookup (cognitive 22): WikipediaLanguageCommandLineUtility.getSiteInfoLookup has cognitive complexity 22 (threshold 15). Drivers by points: boolean chains 17, if/else 2 (3 pts), loops 2 (nesting depth added 1). 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":"Command Line Tools/Update Languages/WikipediaLanguageCommandLineUtility.swift"},"region":{"startLine":72}}}],"partialFingerprints":{"codehealthFindingId/v1":"2e98a04c0e4481264e73fcb14811723e1bc0b7acad7b088bf517ac4e7f66b783"}},{"ruleId":"D2","level":"warning","message":{"text":"WikipediaLanguageCommandLineUtilityAPI.getSites (cognitive 22): WikipediaLanguageCommandLineUtilityAPI.getSites has cognitive complexity 22 (threshold 15). Drivers by points: if/else 9 (15 pts), boolean chains 7 (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":"Command Line Tools/Update Languages/WikipediaLanguageCommandLineUtilityAPI.swift"},"region":{"startLine":22}}}],"partialFingerprints":{"codehealthFindingId/v1":"af459d75540ff933422c9fe4ece991cd0f27b15657bd49456ebffcfe5cf5ab96"}},{"ruleId":"D2","level":"warning","message":{"text":"TableOfContentsAnimator.gestureRecognizerShouldBegin (cognitive 22): TableOfContentsAnimator.gestureRecognizerShouldBegin has cognitive complexity 22 (threshold 15). Drivers by points: if/else 12 (16 pts), boolean chains 4, match/switch 1 (2 pts) (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":"Wikipedia/Code/TableOfContentsAnimator.swift"},"region":{"startLine":313}}}],"partialFingerprints":{"codehealthFindingId/v1":"3b214eca7f644ceac3112aa890c67459f73677a09158713bb4b95c1e7698bf92"}},{"ruleId":"D2","level":"warning","message":{"text":"DatabasePopulationViewModel.populateViewedArticles (cognitive 22): DatabasePopulationViewModel.populateViewedArticles has cognitive complexity 22 (threshold 15). Drivers by points: if/else 7 (13 pts), boolean chains 4, error handling 1 (3 pts), loops 2 (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":"Wikipedia/Code/Database Population/DatabasePopulationViewModel.swift"},"region":{"startLine":110}}}],"partialFingerprints":{"codehealthFindingId/v1":"498f77d738430a6ae43beb74990bb7d94ba0b353c675ed134fc47bd6018b61be"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFFont.\u0060for\u0060 (cognitive 21): WMFFont.\u0060for\u0060 has cognitive complexity 21 (threshold 15). Drivers by points: if/else 10 (20 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":"WMFComponents/Sources/WMFComponents/Style/WMFFont.swift"},"region":{"startLine":61}}}],"partialFingerprints":{"codehealthFindingId/v1":"335fabd68ac4847c9239f2b6aaa0878f3fc59ce0ee6d341b39523023ea30d1d4"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticleFetcher.fetchMediaListURLs (cognitive 21): ArticleFetcher.fetchMediaListURLs has cognitive complexity 21 (threshold 15). Drivers by points: if/else 5 (11 pts), loops 2 (6 pts), boolean chains 3, match/switch 1 (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":"Wikipedia/Code/ArticleFetcher.swift"},"region":{"startLine":51}}}],"partialFingerprints":{"codehealthFindingId/v1":"8016f0da2fe2b12a0aec7f5cd57e5d893beef79001c133aeaf8280455adc36a5"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticlePlaceView.setSelected (cognitive 21): ArticlePlaceView.setSelected has cognitive complexity 21 (threshold 15). Drivers by points: if/else 16 (17 pts), boolean chains 3, ternaries 1 (nesting depth added 1). 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":"Wikipedia/Code/ArticlePlaceView.swift"},"region":{"startLine":408}}}],"partialFingerprints":{"codehealthFindingId/v1":"d48ee02d33b9ec9390c0ed5777c5fdea16d4d29cc3aba7114a6078c349bb8b74"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticleViewController.showFundraisingCampaignAnnouncementIfNeeded (cognitive 21): ArticleViewController.showFundraisingCampaignAnnouncementIfNeeded has cognitive complexity 21 (threshold 15). Drivers by points: if/else 10 (13 pts), boolean chains 8 (nesting depth added 3). 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."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"cf92b1d8fc56027afaa3655f3a693b825004768d92512deaedab09e19cc827b3"}},{"ruleId":"D2","level":"warning","message":{"text":"DiffListChangeItemViewModel.constructAccessibilityLabel (cognitive 21): DiffListChangeItemViewModel.constructAccessibilityLabel has cognitive complexity 21 (threshold 15). Drivers by points: if/else 6 (13 pts), match/switch 3 (6 pts), boolean chains 1, loops 1 (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":"Wikipedia/Code/DiffListChangeItemViewModel.swift"},"region":{"startLine":229}}}],"partialFingerprints":{"codehealthFindingId/v1":"9e442af77067a630c4496f155568e57c8a9f69d7385e50b6214c2e4a01ef4ede"}},{"ruleId":"D2","level":"warning","message":{"text":"ThanksGiving.tappedThank (cognitive 21): ThanksGiving.tappedThank has cognitive complexity 21 (threshold 15). Drivers by points: if/else 13 (14 pts), match/switch 4 (6 pts), boolean chains 1 (nesting depth added 3). 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":"Wikipedia/Code/ThanksGiving.swift"},"region":{"startLine":35}}}],"partialFingerprints":{"codehealthFindingId/v1":"481ed230f4693d77257e287ae11e4610ad74fc59c808ea3bcdf64dd057831711"}},{"ruleId":"D2","level":"warning","message":{"text":"MWKDataStore.migrateWikipediaEntities (cognitive 21): MWKDataStore.migrateWikipediaEntities has cognitive complexity 21 (threshold 15). Drivers by points: loops 4 (10 pts), if/else 3 (7 pts), error handling 2 (4 pts) (nesting depth added 12). 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":"WMF Framework/MWKDataStore\u002BLanguageVariantMigration.swift"},"region":{"startLine":161}}}],"partialFingerprints":{"codehealthFindingId/v1":"b8202c657faa82c00a02ff1d5a938801b1270f08daf4020a0f52ab82bca75840"}},{"ruleId":"D2","level":"warning","message":{"text":"AppleStringsFile.readFromVariable (cognitive 21): AppleStringsFile.readFromVariable has cognitive complexity 21 (threshold 15). Drivers by points: if/else 7 (20 pts), loops 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":"scripts/update-qqq.php"},"region":{"startLine":29}}}],"partialFingerprints":{"codehealthFindingId/v1":"737a442ae6df17fe7552e5b99b19c28640037760b46f905880f30944b0fb3a57"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFSurveyView.body (cognitive 20): WMFSurveyView.body has cognitive complexity 20 (threshold 15). Drivers by points: if/else 11 (13 pts), ternaries 2 (3 pts), loops 1 (2 pts), boolean chains 1, match/switch 1 (nesting depth added 4). 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":"WMFComponents/Sources/WMFComponents/Components/Shared/Survey/WMFSurveyView.swift"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"5a33fe55c45f4174dd42fdfa283a4e6d980f70675940183b5f22230a179b6164"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFArticle.merge (cognitive 20): WMFArticle.merge has cognitive complexity 20 (threshold 15). Drivers by points: if/else 12 (16 pts), boolean chains 3, loops 1 (nesting depth added 4). 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":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"cccac8a9cffe4dd809a6d141de767ecfa096aa5a66a978b3e98007217c66a0b4"}},{"ruleId":"D2","level":"warning","message":{"text":"PermanentlyPersistableURLCache.updateCacheWithCachedResponse (cognitive 20): PermanentlyPersistableURLCache.updateCacheWithCachedResponse has cognitive complexity 20 (threshold 15). Drivers by points: if/else 9, boolean chains 8, match/switch 2, ternaries 1. 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":"WMF Framework/PermanentlyPersistableURLCache.swift"},"region":{"startLine":452}}}],"partialFingerprints":{"codehealthFindingId/v1":"a649f79392518568441beefe9c5e9d86f91de49206df7448a25a49e8fd86ba07"}},{"ruleId":"D2","level":"warning","message":{"text":"ReadingListsSyncOperation.execute (cognitive 20): ReadingListsSyncOperation.execute has cognitive complexity 20 (threshold 15). Drivers by points: if/else 7 (14 pts), boolean chains 3, error handling 2 (3 pts) (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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"a085fdd46858c53b18e9d2647f2c784aa5a8d32444aa4d02682949c1defe35d4"}},{"ruleId":"D2","level":"warning","message":{"text":"WidgetController.fetchFeaturedArticleContent (cognitive 20): WidgetController.fetchFeaturedArticleContent has cognitive complexity 20 (threshold 15). Drivers by points: if/else 11 (18 pts), boolean chains 1, match/switch 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":"WMF Framework/Widget/WidgetController.swift"},"region":{"startLine":489}}}],"partialFingerprints":{"codehealthFindingId/v1":"c19e56ac0f5a0db1a3dffade171bb6b678d0abcecdcb57a29a1db80dcc617152"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFActivityTabViewController.viewDidLoad (cognitive 20): WMFActivityTabViewController.viewDidLoad has cognitive complexity 20 (threshold 15). Drivers by points: if/else 11 (17 pts), boolean chains 3 (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":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"d7c4fbfc9097d7628c63b4a9492c1f43e9f3149bc420b8a501b6e5977ed4a45a"}},{"ruleId":"D2","level":"warning","message":{"text":"EditorViewController.loadContent (cognitive 20): EditorViewController.loadContent has cognitive complexity 20 (threshold 15). Drivers by points: if/else 12, boolean chains 6, match/switch 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":"Wikipedia/Code/EditorViewController.swift"},"region":{"startLine":192}}}],"partialFingerprints":{"codehealthFindingId/v1":"0a9de5fbc978bdf51eb1075ab7f85897365dc77daf9bc7272e525f8f2f03d024"}},{"ruleId":"D2","level":"warning","message":{"text":"ColumnarCollectionViewLayout.layoutAttributesForElements (cognitive 19): ColumnarCollectionViewLayout.layoutAttributesForElements has cognitive complexity 19 (threshold 15). Drivers by points: if/else 5 (12 pts), loops 4 (7 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":"WMF Framework/ColumnarCollectionViewLayout.swift"},"region":{"startLine":35}}}],"partialFingerprints":{"codehealthFindingId/v1":"991df9d63892ad5d848136d78c78e0328e33861853aaa3e6573bbb6d089d30b6"}},{"ruleId":"D2","level":"warning","message":{"text":"PageNamespace.isTalkBased (cognitive 19): PageNamespace.isTalkBased has cognitive complexity 19 (threshold 15). Drivers by points: boolean chains 19. 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":"WMF Framework/PageNamespace.swift"},"region":{"startLine":91}}}],"partialFingerprints":{"codehealthFindingId/v1":"c98aa242d38ada69cfde8c7446eb1692770ffc8d5d751e81b13f4070bd3af650"}},{"ruleId":"D2","level":"warning","message":{"text":"RemoteNotificationsController.predicateForFilterSavedState (cognitive 19): RemoteNotificationsController.predicateForFilterSavedState has cognitive complexity 19 (threshold 15). Drivers by points: if/else 10 (13 pts), boolean chains 4, match/switch 1, ternaries 1 (nesting depth added 3). 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":"WMF Framework/Remote Notifications/RemoteNotificationsController.swift"},"region":{"startLine":404}}}],"partialFingerprints":{"codehealthFindingId/v1":"bb71e002e7c070c9de4c5ee5e5bde45a312c1a8e0ede59964664bb82b37e5a58"}},{"ruleId":"D2","level":"warning","message":{"text":"ActivityTabFunnel.logActivityTabCustomizeExit (cognitive 19): ActivityTabFunnel.logActivityTabCustomizeExit has cognitive complexity 19 (threshold 15). Drivers by points: ternaries 5 (9 pts), boolean chains 7, if/else 3 (nesting depth added 4). 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":"Wikipedia/Code/ActivityTabFunnel.swift"},"region":{"startLine":136}}}],"partialFingerprints":{"codehealthFindingId/v1":"38814beda25e498aabcd9562ca2fc3b26ebb887780cd9203e8d40c26cdd8b37a"}},{"ruleId":"D2","level":"warning","message":{"text":"AppearanceSettingsViewController.tableView (cognitive 19): AppearanceSettingsViewController.tableView has cognitive complexity 19 (threshold 15). Drivers by points: if/else 11 (14 pts), ternaries 1 (3 pts), boolean chains 2 (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":"Wikipedia/Code/AppearanceSettingsViewController.swift"},"region":{"startLine":158}}}],"partialFingerprints":{"codehealthFindingId/v1":"03cc9fc973a6ce02413140b9a761c8c32a2031a928eed53425f583c84f00b82e"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticleViewController.showNewDonateExperienceCampaignModal (cognitive 19): ArticleViewController.showNewDonateExperienceCampaignModal has cognitive complexity 19 (threshold 15). Drivers by points: if/else 11 (15 pts), boolean chains 3, match/switch 1 (nesting depth added 4). 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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":108}}}],"partialFingerprints":{"codehealthFindingId/v1":"8e96b7668199fb422f0c9f6f245dd97b72b4f137f574b785a7687bd10633ca1f"}},{"ruleId":"D2","level":"warning","message":{"text":"DiffContainerViewController.evaluateState (cognitive 19): DiffContainerViewController.evaluateState has cognitive complexity 19 (threshold 15). Drivers by points: match/switch 6 (10 pts), if/else 7 (9 pts) (nesting depth added 6). 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":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":534}}}],"partialFingerprints":{"codehealthFindingId/v1":"54731b620fbb362aa56109fd978fa6a9918ea3c0b9279722ab008eb94f4582bd"}},{"ruleId":"D2","level":"warning","message":{"text":"DiffListChangeItemViewModel.calculateTextPaddingAndInBetweenSpacing (cognitive 19): DiffListChangeItemViewModel.calculateTextPaddingAndInBetweenSpacing has cognitive complexity 19 (threshold 15). Drivers by points: boolean chains 7, if/else 5 (7 pts), ternaries 2 (4 pts), match/switch 1 (nesting depth added 4). 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":"Wikipedia/Code/DiffListChangeItemViewModel.swift"},"region":{"startLine":99}}}],"partialFingerprints":{"codehealthFindingId/v1":"dbf9199b6b3f0ba3ec500544808a36ec4e8cad396cda0cea3fb989a12cbfa1c9"}},{"ruleId":"D2","level":"warning","message":{"text":"DiffListViewController.updateListViewModels (cognitive 19): DiffListViewController.updateListViewModels has cognitive complexity 19 (threshold 15). Drivers by points: if/else 4 (11 pts), loops 3 (6 pts), boolean chains 1, 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":"Wikipedia/Code/DiffListViewController.swift"},"region":{"startLine":157}}}],"partialFingerprints":{"codehealthFindingId/v1":"5fd24465f8f7b0ba58fd12b7b3a4fa1566777be5cf653a13d999bad569b5f2ec"}},{"ruleId":"D2","level":"warning","message":{"text":"PlacesViewController.handlePanGesture (cognitive 19): PlacesViewController.handlePanGesture has cognitive complexity 19 (threshold 15). Drivers by points: if/else 10 (18 pts), match/switch 1 (nesting depth added 8). 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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":1057}}}],"partialFingerprints":{"codehealthFindingId/v1":"2ea9efe93e05fc5d97600feb895a9dd3c7279768214e4dab77da90bf840b65a1"}},{"ruleId":"D2","level":"warning","message":{"text":"SceneDelegate.openURLContexts (cognitive 19): SceneDelegate.openURLContexts has cognitive complexity 19 (threshold 15). Drivers by points: if/else 12 (17 pts), boolean chains 2 (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":"Wikipedia/Code/SceneDelegate.swift"},"region":{"startLine":176}}}],"partialFingerprints":{"codehealthFindingId/v1":"88f897476df2e87ca022dcac06685424eb375c03b327c7e81a60798e7ae61cc4"}},{"ruleId":"D2","level":"warning","message":{"text":"SinglePageWebViewController.handleNavigation (cognitive 19): SinglePageWebViewController.handleNavigation has cognitive complexity 19 (threshold 15). Drivers by points: if/else 8 (13 pts), boolean chains 4, match/switch 1 (2 pts) (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":"Wikipedia/Code/SinglePageWebViewController.swift"},"region":{"startLine":389}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c2fccfcc32c7431eacaeffaf2a6e15fc1e41e309489267b1de373258bb5f65e"}},{"ruleId":"D2","level":"warning","message":{"text":"TalkPageViewController.scrollToFindInPageResultRect (cognitive 19): TalkPageViewController.scrollToFindInPageResultRect has cognitive complexity 19 (threshold 15). Drivers by points: if/else 7 (18 pts), boolean chains 1 (nesting depth added 11). 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":"Wikipedia/Code/TalkPageViewController.swift"},"region":{"startLine":48}}}],"partialFingerprints":{"codehealthFindingId/v1":"51c3427ab6fef7b01381adc7efe38faadcc1fba26952f7e3406ae5d076857ad8"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFAccountCreationViewController.createAccount (cognitive 19): WMFAccountCreationViewController.createAccount has cognitive complexity 19 (threshold 15). Drivers by points: if/else 10 (16 pts), match/switch 1 (2 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":"Wikipedia/Code/WMFAccountCreationViewController.swift"},"region":{"startLine":517}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c19fbae506dcd6bf916b2458416c6d3328bc47968d04228fa69a8d831b30089"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFAppViewController.logWatchlistUserDidSaveFilterSettings (cognitive 19): WMFAppViewController.logWatchlistUserDidSaveFilterSettings has cognitive complexity 19 (threshold 15). Drivers by points: match/switch 7 (9 pts), if/else 6 (7 pts), boolean chains 2, loops 1 (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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":495}}}],"partialFingerprints":{"codehealthFindingId/v1":"0c623ce9000891627fcad7a7e1496f889bd43c98163315c92531a8b72304a023"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFAppViewController.logTabBarSelectionsForActivityTab (cognitive 19): WMFAppViewController.logTabBarSelectionsForActivityTab has cognitive complexity 19 (threshold 15). Drivers by points: if/else 14 (16 pts), boolean chains 3 (nesting depth added 2). 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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":1261}}}],"partialFingerprints":{"codehealthFindingId/v1":"8660945773d80aed838ca0edfd76c6dfee5a769825bd413ffeecc328d05f0b79"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFHCaptchaViewController.setupHCaptcha (cognitive 19): WMFHCaptchaViewController.setupHCaptcha has cognitive complexity 19 (threshold 15). Drivers by points: if/else 6 (8 pts), boolean chains 5, ternaries 2 (4 pts), error handling 1, match/switch 1 (nesting depth added 4). 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":"Wikipedia/Code/WMFHCaptchaViewController.swift"},"region":{"startLine":98}}}],"partialFingerprints":{"codehealthFindingId/v1":"6402bcd368456f7ec0be815bc671fdf3ded1d5e86aa382276f12b5a5605a3cea"}},{"ruleId":"D2","level":"warning","message":{"text":"WikidataFetcher.processResponse (cognitive 19): WikidataFetcher.processResponse has cognitive complexity 19 (threshold 15). Drivers by points: if/else 10 (14 pts), match/switch 1 (3 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":"Wikipedia/Code/WikidataFetcher.swift"},"region":{"startLine":197}}}],"partialFingerprints":{"codehealthFindingId/v1":"bfe4719132cc91e11eb527557153d266984baee3c283a5f4e4e8eb9ce738fe18"}},{"ruleId":"D2","level":"warning","message":{"text":"MWKDataStore.migrateNewVariants (cognitive 19): MWKDataStore.migrateNewVariants has cognitive complexity 19 (threshold 15). Drivers by points: loops 4 (10 pts), error handling 4 (8 pts), if/else 1 (nesting depth added 10). 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":"WMF Framework/MWKDataStore\u002BLanguageVariantMigration.swift"},"region":{"startLine":110}}}],"partialFingerprints":{"codehealthFindingId/v1":"3efe7231b7a9222f4a1669df2f051058e3f2e23f1224ae753dbd19d35bac0ae4"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFContentGroup.detailViewControllerWithDataStore (cognitive 19): WMFContentGroup.detailViewControllerWithDataStore has cognitive complexity 19 (threshold 15). Drivers by points: if/else 7 (11 pts), ternaries 2 (4 pts), match/switch 2 (3 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":"WMF Framework/WMFContentGroup\u002BDisplay.swift"},"region":{"startLine":34}}}],"partialFingerprints":{"codehealthFindingId/v1":"64193f6149b07724aa244c739b18842966e5cb5eae4f425bda6ada2cbdd6bbe6"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFDonateViewModel.paymentAuthorizationController (cognitive 18): WMFDonateViewModel.paymentAuthorizationController has cognitive complexity 18 (threshold 15). Drivers by points: if/else 9 (11 pts), match/switch 2 (4 pts), boolean chains 3 (nesting depth added 4). 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":"WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift"},"region":{"startLine":546}}}],"partialFingerprints":{"codehealthFindingId/v1":"299aaf47f8246b2db1709a981c00d9a9a6e7a344f8d2a84f5c2656dd78c9f2bd"}},{"ruleId":"D2","level":"warning","message":{"text":"ColumnarCollectionViewLayoutSection.invalidate (cognitive 18): ColumnarCollectionViewLayoutSection.invalidate has cognitive complexity 18 (threshold 15). Drivers by points: if/else 6 (12 pts), loops 1 (3 pts), match/switch 2 (3 pts) (nesting depth added 9). 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":"WMF Framework/ColumarCollectionViewLayoutSection.swift"},"region":{"startLine":155}}}],"partialFingerprints":{"codehealthFindingId/v1":"ef76607bf1b2e55b623aeda0a1e78ca721e876deade81091efd2774ad8b88589"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticlePlaceView.set (cognitive 18): ArticlePlaceView.set has cognitive complexity 18 (threshold 15). Drivers by points: if/else 15 (16 pts), boolean chains 2 (nesting depth added 1). 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":"Wikipedia/Code/ArticlePlaceView.swift"},"region":{"startLine":191}}}],"partialFingerprints":{"codehealthFindingId/v1":"c4716f3bb8fdf78977b23b587ea3710055f757b178c80bf5016d718a47263c88"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticleToolbarController.createMoreMenu (cognitive 18): ArticleToolbarController.createMoreMenu has cognitive complexity 18 (threshold 15). Drivers by points: if/else 9 (13 pts), ternaries 3 (5 pts) (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":"Wikipedia/Code/ArticleToolbarController.swift"},"region":{"startLine":125}}}],"partialFingerprints":{"codehealthFindingId/v1":"05e6f518fcec1e46e46f40ab67341dd8c7102437ba5e0d7e854ab21f15d39add"}},{"ruleId":"D2","level":"warning","message":{"text":"DonateCoordinator.nativeDonateFormViewModel (cognitive 18): DonateCoordinator.nativeDonateFormViewModel has cognitive complexity 18 (threshold 15). Drivers by points: if/else 10, boolean chains 5, loops 1 (2 pts), match/switch 1 (nesting depth added 1). 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":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":461}}}],"partialFingerprints":{"codehealthFindingId/v1":"47ca709dc7c0cdf1f4ea589c528ee12d83c55bc38312ed1c26e73d8c4157f099"}},{"ruleId":"D2","level":"warning","message":{"text":"ExploreViewController.exploreCardViewController (cognitive 18): ExploreViewController.exploreCardViewController has cognitive complexity 18 (threshold 15). Drivers by points: if/else 13 (16 pts), boolean chains 1, match/switch 1 (nesting depth added 3). 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":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":792}}}],"partialFingerprints":{"codehealthFindingId/v1":"620f8e88100730f2e3584876ec12ce64206422804a381bb19447ab4b24df73e4"}},{"ruleId":"D2","level":"warning","message":{"text":"PageHistoryViewController.getEditCounts (cognitive 18): PageHistoryViewController.getEditCounts has cognitive complexity 18 (threshold 15). Drivers by points: if/else 6 (12 pts), match/switch 4 (5 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":"Wikipedia/Code/PageHistoryViewController.swift"},"region":{"startLine":189}}}],"partialFingerprints":{"codehealthFindingId/v1":"6c310675be3b503494711f55ca645c8283eca439fe1c2edeb239f8bb93a3c042"}},{"ruleId":"D2","level":"warning","message":{"text":"SavedAllArticlesCoordinator.determineAlertType (cognitive 18): SavedAllArticlesCoordinator.determineAlertType has cognitive complexity 18 (threshold 15). Drivers by points: if/else 10 (13 pts), match/switch 3 (5 pts) (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":"Wikipedia/Code/SavedAllArticlesCoordinator.swift"},"region":{"startLine":359}}}],"partialFingerprints":{"codehealthFindingId/v1":"88a1217287bad892cd915c065cfbb3ee0e19e9c9662da67137519534b5ac7243"}},{"ruleId":"D2","level":"warning","message":{"text":"SessionDelegate.urlSession (cognitive 18): SessionDelegate.urlSession has cognitive complexity 18 (threshold 15). Drivers by points: if/else 7 (13 pts), boolean chains 5 (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":"Wikipedia/Code/Session.swift"},"region":{"startLine":736}}}],"partialFingerprints":{"codehealthFindingId/v1":"159700dbed725712b7de616326d4215879cca1f7e23164277b3601e45e52a138"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFArticleTabsViewModel.prefetchBatch (cognitive 17): WMFArticleTabsViewModel.prefetchBatch has cognitive complexity 17 (threshold 15). Drivers by points: ternaries 2 (6 pts), if/else 4 (5 pts), boolean chains 2, error handling 1 (2 pts), loops 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":"WMFComponents/Sources/WMFComponents/Components/Article Tabs/WMFArticleTabsViewModel.swift"},"region":{"startLine":330}}}],"partialFingerprints":{"codehealthFindingId/v1":"573a8d1b79892979c830843e6b3b6d87a9723f95cf9b9cfc32d7e370cf1b4bd7"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFCommunityFeedView.feedList (cognitive 17): WMFCommunityFeedView.feedList has cognitive complexity 17 (threshold 15). Drivers by points: boolean chains 10, if/else 7. 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":"WMFComponents/Sources/WMFComponents/Components/Home/WMFCommunityFeedView.swift"},"region":{"startLine":39}}}],"partialFingerprints":{"codehealthFindingId/v1":"2204dc0a7480bec006280d7351a9b3140f13d47f354b5c9b51a5ff3410dec02c"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFDonateDataController.submitPayment (cognitive 17): WMFDonateDataController.submitPayment has cognitive complexity 17 (threshold 15). Drivers by points: if/else 10, ternaries 3 (4 pts), match/switch 2 (3 pts) (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":"WMFData/Sources/WMFData/Data Controllers/Donor Experience/WMFDonateDataController.swift"},"region":{"startLine":204}}}],"partialFingerprints":{"codehealthFindingId/v1":"809d7aeb03b6a4ab1bf9b29c64824e7e8ee2be0a309cb20564d7d087546a0c1a"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFGamesDataController.makeWhichCameFirstQuestions (cognitive 17): WMFGamesDataController.makeWhichCameFirstQuestions has cognitive complexity 17 (threshold 15). Drivers by points: ternaries 3 (6 pts), boolean chains 5, if/else 4 (5 pts), loops 1 (nesting depth added 4). 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":"WMFData/Sources/WMFData/Data Controllers/Games/WMFGamesDataController.swift"},"region":{"startLine":363}}}],"partialFingerprints":{"codehealthFindingId/v1":"39fdad47d429288312f49f65a7bb33e146856637ae7efca072ef43c6461d339b"}},{"ruleId":"D2","level":"warning","message":{"text":"DiffFetcher.fetchWikitext (cognitive 17): DiffFetcher.fetchWikitext has cognitive complexity 17 (threshold 15). Drivers by points: if/else 6 (11 pts), loops 2 (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":"Wikipedia/Code/DiffFetcher.swift"},"region":{"startLine":44}}}],"partialFingerprints":{"codehealthFindingId/v1":"b49277fd0fae5db2f862a2da76ef4539b481f1ec3037a1849d09fd93a5c051c5"}},{"ruleId":"D2","level":"warning","message":{"text":"ExploreFeedSettingsViewController.settingsTableViewCell (cognitive 17): ExploreFeedSettingsViewController.settingsTableViewCell has cognitive complexity 17 (threshold 15). Drivers by points: if/else 11 (16 pts), boolean chains 1 (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":"Wikipedia/Code/ExploreFeedSettingsViewController.swift"},"region":{"startLine":357}}}],"partialFingerprints":{"codehealthFindingId/v1":"9b9b1f5b4776f9e98228e6471d53941ced661419d0e8694adb4ff2e790b50fff"}},{"ruleId":"D2","level":"warning","message":{"text":"OldTalkPageReplyCell.sizeThatFits (cognitive 17): OldTalkPageReplyCell.sizeThatFits has cognitive complexity 17 (threshold 15). Drivers by points: if/else 9 (10 pts), ternaries 3 (6 pts), boolean chains 1 (nesting depth added 4). 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":"Wikipedia/Code/OldTalkPageReplyCell.swift"},"region":{"startLine":34}}}],"partialFingerprints":{"codehealthFindingId/v1":"ca70538413dc06c32d8d267d2fe8050e27cf9491c988ce462fb49e47850390c5"}},{"ruleId":"D2","level":"warning","message":{"text":"TalkPageReplyComposeController.userDidPanContainerView (cognitive 17): TalkPageReplyComposeController.userDidPanContainerView has cognitive complexity 17 (threshold 15). Drivers by points: if/else 8 (12 pts), boolean chains 4, match/switch 1 (nesting depth added 4). 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":"Wikipedia/Code/TalkPageReplyComposeController.swift"},"region":{"startLine":257}}}],"partialFingerprints":{"codehealthFindingId/v1":"1a0c23e619c7f416c1b9eea49e01f6e1e422195ba173ecc78fe630e39b8abf84"}},{"ruleId":"D2","level":"warning","message":{"text":"WikimediaProject.init (cognitive 17): WikimediaProject.init has cognitive complexity 17 (threshold 15). Drivers by points: if/else 14, boolean chains 3. 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":"Wikipedia/Code/WikimediaProject.swift"},"region":{"startLine":92}}}],"partialFingerprints":{"codehealthFindingId/v1":"a78ec056e13cd5848f88c348791f99a7afd12d35261f265bceaf845105ab4847"}},{"ruleId":"D2","level":"warning","message":{"text":"UIView.wmf_preferredFrame (cognitive 17): UIView.wmf_preferredFrame has cognitive complexity 17 (threshold 15). Drivers by points: if/else 9, boolean chains 6, match/switch 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":"WMF Framework/UIStackView\u002BSubviewVerification.swift"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"0feea1ab0f2d6e49a2a257ab8d3310404a5919fc9a266670740984c7cf507602"}},{"ruleId":"D2","level":"warning","message":{"text":"localization.swift.writeStrings (cognitive 17): localization.swift.writeStrings has cognitive complexity 17 (threshold 15). Drivers by points: if/else 5 (12 pts), loops 1 (3 pts), boolean chains 1, error handling 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":"Command Line Tools/Update Localizations/localization.swift"},"region":{"startLine":297}}}],"partialFingerprints":{"codehealthFindingId/v1":"de237d9eb2f48fc40bd22883eefcd5cfa2854a37075f644d26493c254beda142"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFBasicService.performGET (cognitive 16): WMFBasicService.performGET has cognitive complexity 16 (threshold 15). Drivers by points: if/else 9 (12 pts), boolean chains 2, loops 1 (2 pts) (nesting depth added 4). 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":"WMFData/Sources/WMFData/Service/WMFBasicService.swift"},"region":{"startLine":148}}}],"partialFingerprints":{"codehealthFindingId/v1":"2a179517b00f705265b08aa87d91cac2df5c59535de42c49155ab26dca74feff"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFGamesDataController.fetchWhichCameFirstStats (cognitive 16): WMFGamesDataController.fetchWhichCameFirstStats has cognitive complexity 16 (threshold 15). Drivers by points: if/else 6 (8 pts), boolean chains 6, loops 1, ternaries 1 (nesting depth added 2). 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":"WMFData/Sources/WMFData/Data Controllers/Games/WMFGamesDataController.swift"},"region":{"startLine":195}}}],"partialFingerprints":{"codehealthFindingId/v1":"525106c6e2e665f084a91b29e2bc71fdc4a07ba30d622137f26d10783ec74939"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFYearInReviewDataController.populateYearInReviewReportData (cognitive 16): WMFYearInReviewDataController.populateYearInReviewReportData has cognitive complexity 16 (threshold 15). Drivers by points: if/else 6 (10 pts), loops 3, error handling 1 (2 pts), boolean chains 1 (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":"WMFData/Sources/WMFData/Data Controllers/Year In Review/WMFYearInReviewDataController.swift"},"region":{"startLine":478}}}],"partialFingerprints":{"codehealthFindingId/v1":"f21243415c494a296d4ee4ee50242ff64bd3ab8f2546c768c28977926c92e44d"}},{"ruleId":"D2","level":"warning","message":{"text":"ExploreFeedPreferencesUpdateCoordinator.coordinateUpdate (cognitive 16): ExploreFeedPreferencesUpdateCoordinator.coordinateUpdate has cognitive complexity 16 (threshold 15). Drivers by points: if/else 9 (15 pts), boolean chains 1 (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":"WMF Framework/ExploreFeedPreferencesUpdateCoordinator.swift"},"region":{"startLine":22}}}],"partialFingerprints":{"codehealthFindingId/v1":"8cc752bb8cc92965b6c8049ffdad6fa544d4d6d53344ab0e0b3091978e6af7e2"}},{"ruleId":"D2","level":"warning","message":{"text":"ReadingListsAPIController.addEntriesToList (cognitive 16): ReadingListsAPIController.addEntriesToList has cognitive complexity 16 (threshold 15). Drivers by points: if/else 8 (10 pts), ternaries 1 (3 pts), loops 1 (2 pts), boolean chains 1 (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":"WMF Framework/ReadingListsAPIController.swift"},"region":{"startLine":352}}}],"partialFingerprints":{"codehealthFindingId/v1":"8d1e216835eacee927c63ff90bdaf344811b89c2b3906b62d951a0727aa3c3b9"}},{"ruleId":"D2","level":"warning","message":{"text":"ArticleCacheDBWriter.add (cognitive 16): ArticleCacheDBWriter.add has cognitive complexity 16 (threshold 15). Drivers by points: if/else 3 (7 pts), loops 2 (4 pts), match/switch 2 (3 pts), error handling 1 (2 pts) (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":"Wikipedia/Code/ArticleCacheDBWriter.swift"},"region":{"startLine":43}}}],"partialFingerprints":{"codehealthFindingId/v1":"82f9e25683d9dc691385b57e91e84349ab009045d760ea61b02f1527de2740b5"}},{"ruleId":"D2","level":"warning","message":{"text":"EditSaveViewController.handleEditSuccess (cognitive 16): EditSaveViewController.handleEditSuccess has cognitive complexity 16 (threshold 15). Drivers by points: if/else 8 (12 pts), boolean chains 4 (nesting depth added 4). 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":"Wikipedia/Code/EditSaveViewController.swift"},"region":{"startLine":523}}}],"partialFingerprints":{"codehealthFindingId/v1":"484fdfe0948fff1545424e2bd17513c9dffe9d4d29d0ba35f8a2f19a54cffb2b"}},{"ruleId":"D2","level":"warning","message":{"text":"InsertMediaSearchViewController.search (cognitive 16): InsertMediaSearchViewController.search has cognitive complexity 16 (threshold 15). Drivers by points: if/else 10 (13 pts), boolean chains 2, loops 1 (nesting depth added 3). 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":"Wikipedia/Code/InsertMediaSearchViewController.swift"},"region":{"startLine":48}}}],"partialFingerprints":{"codehealthFindingId/v1":"e982580ec28867027cb8a52b5ccd146fc5a21acf50b354f0d130c46e2890085b"}},{"ruleId":"D2","level":"warning","message":{"text":"TalkPageArchivesView.body (cognitive 16): TalkPageArchivesView.body has cognitive complexity 16 (threshold 15). Drivers by points: if/else 6 (10 pts), error handling 2 (4 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":"Wikipedia/Code/TalkPageArchivesView.swift"},"region":{"startLine":30}}}],"partialFingerprints":{"codehealthFindingId/v1":"9ef4f403d67526a4d668c6df68723ad862ab93172f2d31ef4857ecd0e2ff55c6"}},{"ruleId":"D2","level":"warning","message":{"text":"TalkPageTopicComposeViewController.tappedPublish (cognitive 16): TalkPageTopicComposeViewController.tappedPublish has cognitive complexity 16 (threshold 15). Drivers by points: if/else 8 (10 pts), boolean chains 4, match/switch 1 (2 pts) (nesting depth added 3). 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":"Wikipedia/Code/TalkPageTopicComposeViewController.swift"},"region":{"startLine":535}}}],"partialFingerprints":{"codehealthFindingId/v1":"71d833c77c40c69b96034868e2869316f3b744cb8c942b76cd526d504ffb9d72"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFAccountCreator.createAccount (cognitive 16): WMFAccountCreator.createAccount has cognitive complexity 16 (threshold 15). Drivers by points: if/else 9 (12 pts), match/switch 1 (3 pts), boolean chains 1 (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":"Wikipedia/Code/WMFAccountCreator.swift"},"region":{"startLine":162}}}],"partialFingerprints":{"codehealthFindingId/v1":"6c91c6f555986af742d36d498a5e485f6420a56d00c6536df4a27f45fc1df526"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFAppViewController.configureTabController (cognitive 16): WMFAppViewController.configureTabController has cognitive complexity 16 (threshold 15). Drivers by points: if/else 7 (9 pts), boolean chains 3, loops 1 (2 pts), match/switch 1 (2 pts) (nesting depth added 4). 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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":367}}}],"partialFingerprints":{"codehealthFindingId/v1":"a276e3d6ca0b3fa273efcec92b63dacc8db2a1b235f0e2c20cb2bf49a3d5adc7"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFAuthenticationManager.logout (cognitive 16): WMFAuthenticationManager.logout has cognitive complexity 16 (threshold 15). Drivers by points: if/else 11 (13 pts), boolean chains 3 (nesting depth added 2). 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":"Wikipedia/Code/WMFAuthenticationManager.swift"},"region":{"startLine":425}}}],"partialFingerprints":{"codehealthFindingId/v1":"ab46299e8e12860707d03dd00d21bf4e5a92285066fcc487cff238596fb80051"}},{"ruleId":"D2","level":"warning","message":{"text":"WMFLoginViewController.save (cognitive 16): WMFLoginViewController.save has cognitive complexity 16 (threshold 15). Drivers by points: if/else 8 (11 pts), match/switch 2 (4 pts), boolean chains 1 (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":"Wikipedia/Code/WMFLoginViewController.swift"},"region":{"startLine":233}}}],"partialFingerprints":{"codehealthFindingId/v1":"916567fecea496903b6cf8e87511db060890f79c377ef0ebcf51bcbd27b881ee"}},{"ruleId":"D2","level":"warning","message":{"text":"WikitextFetcher.fetchSection (cognitive 16): WikitextFetcher.fetchSection has cognitive complexity 16 (threshold 15). Drivers by points: if/else 6 (8 pts), boolean chains 7, match/switch 1 (nesting depth added 2). 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":"Wikipedia/Code/WikitextFetcher.swift"},"region":{"startLine":74}}}],"partialFingerprints":{"codehealthFindingId/v1":"8dbfc473bf573c5f4d75a7cefc12896666e984373f60a656edde7a6fad3536ce"}},{"ruleId":"D2","level":"warning","message":{"text":"UIViewController.push (cognitive 16): UIViewController.push has cognitive complexity 16 (threshold 15). Drivers by points: if/else 10 (16 pts) (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":"Wikipedia/Code/FundraisingAnnouncementPanel.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"2d31a9f42a17e446792d5f0374dd82e505c8b72a5ae648365794f65765a2a64e"}},{"ruleId":"D2","level":"warning","message":{"text":"Locale.uniqueWikipediaLanguages (cognitive 16): Locale.uniqueWikipediaLanguages has cognitive complexity 16 (threshold 15). Drivers by points: if/else 5 (12 pts), ternaries 1 (3 pts), loops 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":"Wikipedia/Code/NSLocale\u002BWMFExtras.swift"},"region":{"startLine":52}}}],"partialFingerprints":{"codehealthFindingId/v1":"b71ccd8f20e36427b17425e56459d21b4aed2a5dbb8df6390b10c439ff3cf031"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: WMFAppViewController.processLinkUserActivity: MethodTooLong \u2014 processLinkUserActivity runs 1152 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 1052 over it, 11.52\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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":42}}}],"partialFingerprints":{"codehealthFindingId/v1":"69a57891a325c82fa44fd59b0a76b8ff68b7111d891f76a5d88456a6af0a8bd6"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: ArticleViewController: TooManyMethods \u2014 250 methods. The bar is 30 methods; this is 220 over it, 8.33\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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":10}}}],"partialFingerprints":{"codehealthFindingId/v1":"45e37619f7ca9134be512859fc6e269a2bc3b542f781351cc3315ebedbfe03a0"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: ArticleViewController.eventLoggingLabel: MethodTooLong \u2014 eventLoggingLabel runs 832 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 732 over it, 8.32\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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":2}}}],"partialFingerprints":{"codehealthFindingId/v1":"701b43b2576b05d499e198df8947d8677f45ad0d36d50803d2d4ab26cbf12507"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: ArticleViewController.shareMenuItemTapped: MethodTooLong \u2014 shareMenuItemTapped runs 831 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 731 over it, 8.31\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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":3}}}],"partialFingerprints":{"codehealthFindingId/v1":"9cfd0e1d64a869a3906e29238cfd289365ff2ecb7f690249ffddea562e96bb2a"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: ArticleViewController.navigationToolbar: MethodTooLong \u2014 navigationToolbar runs 829 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 729 over it, 8.29\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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":5}}}],"partialFingerprints":{"codehealthFindingId/v1":"eae90aa39985f46f2f464f54d8fe199e7272cff8fcc249dcc75dc2b56e67aafa"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: ArticleViewController.didReceive: MethodTooLong \u2014 didReceive runs 826 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 726 over it, 8.26\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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"3186cd1442902633d9dcda121db019d228da2fedba37141a255e0bf8da7f3541"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: ArticleViewController.referenceViewControllerUserDidTapClose: MethodTooLong \u2014 referenceViewControllerUserDidTapClose runs 824 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 724 over it, 8.24\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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"e1efbe0e4caab6f46ce2aa1239b7506bd81417f4da4616e87cb4bfe0ead76db2"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: WMFAppViewController: TooManyMethods \u2014 188 methods. The bar is 30 methods; this is 158 over it, 6.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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":43}}}],"partialFingerprints":{"codehealthFindingId/v1":"52236fc9cd5ec40fc6c4b87dcc2a0f3a16c7ef8f561b600a8281c7831cba4ff3"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: WMFArticle.quadKey: MethodTooLong \u2014 quadKey runs 495 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 395 over it, 4.95\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":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"fad2a1825f0cd55b4201632c28597d5e43dd26d0243022194b12e93147343d3d"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: WMFArticle.hasChangedValuesForCurrentEventThatAffectSavedArticlesFetch: MethodTooLong \u2014 hasChangedValuesForCurrentEventThatAffectSavedArticlesFetch runs 495 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 395 over it, 4.95\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":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"4eebf7b2943957ad1fdbdc0287d362d429ea47ae4a511e69c2af90a5ca2a3978"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: ExploreViewController: TooManyMethods \u2014 147 methods. The bar is 30 methods; this is 117 over it, 4.90\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":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"168fdec621e80880b9c57cb77fbab96503ad6a7b4d4b8d87007ad4fa767f341a"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: DonateFunnel: TooManyMethods \u2014 120 methods. The bar is 30 methods; this is 90 over it, 4.00\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":"Wikipedia/Code/DonateFunnel.swift"},"region":{"startLine":5}}}],"partialFingerprints":{"codehealthFindingId/v1":"b76b4736014793a5b0a71acfcf6f3b5ec4adf7712e969c030a03af300a2d036b"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: PlacesViewController: ClassTooLong \u2014 1575 significant lines (blank, comment-only and punctuation-only lines excluded), 108 methods. The bar is 400 significant lines; this is 1175 over it, 3.94\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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"257120b6c117974b9b3c6f2d856a4c10759ab24334721b9ffbaedb6995cafd8a"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: PlacesViewController: TooManyMethods \u2014 108 methods. The bar is 30 methods; this is 78 over it, 3.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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"b481def050a221b99c0a200da01d1457e83de9bd0e2eb7dee74987add37cf60f"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: Error.logDescription: MethodTooLong \u2014 logDescription runs 349 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 249 over it, 3.49\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":"WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"e7ef13ccace0e66d754176e7007d864347f5503399dfcfcb43424df9d35c2673"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/PlacesViewController.swift: FileTooLong \u2014 1725 significant lines (blank, comment-only and punctuation-only lines excluded), about 91% of them inside a single declaration: PlacesViewController (10-2404). The bar is 500 significant lines; this is 1225 over it, 3.45\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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"0884c1dd7552f30236024407286a4ae62fa0c541dfff3e3220369b9fb88428f8"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: TalkPageViewController: TooManyMethods \u2014 98 methods. The bar is 30 methods; this is 68 over it, 3.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":"Wikipedia/Code/TalkPageViewController.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"98b06073a1866401ff597211d990dd1d73e9d2d440a70f6fd7eafbe8f2467434"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/WMFAppViewController.swift: FileTooLong \u2014 1532 significant lines (blank, comment-only and punctuation-only lines excluded), about 75% of them inside a single declaration: WMFAppViewController (43-1824). The bar is 500 significant lines; this is 1032 over it, 3.06\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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"78a649d903cc230a1fca740ab800c2b9ed6ee762fbc7120e4db45a34081daa22"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: SearchResultsViewController.semanticSearchHiddenToastTitle: MethodTooLong \u2014 semanticSearchHiddenToastTitle runs 301 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 201 over it, 3.01\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":"Wikipedia/Code/SearchResultsViewController.swift"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"1b0102724f034f81f9e1bbe6c8dde25364d6ff7a7b17f8a42776086ea427572c"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: WMFAppViewController: ClassTooLong \u2014 1152 significant lines (blank, comment-only and punctuation-only lines excluded), 188 methods. The bar is 400 significant lines; this is 752 over it, 2.88\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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":43}}}],"partialFingerprints":{"codehealthFindingId/v1":"04301dfbab78a16ef11550aa63db2922b983478177db3402e6901cfc2f808486"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: WMFSFSymbolIcon.\u0060for\u0060: MethodTooLong \u2014 \u0060for\u0060 runs 285 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 185 over it, 2.85\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":"WMFComponents/Sources/WMFComponents/Style/WMFIcon.swift"},"region":{"startLine":203}}}],"partialFingerprints":{"codehealthFindingId/v1":"ebfe1cca95d018e680297e78ba5c4f9ff30809b6226403a2f4e652bb1dba6bff"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: TokenType.wmfTokenType: MethodTooLong \u2014 wmfTokenType runs 270 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 170 over it, 2.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":"WMF Framework/Fetcher.swift"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"bc0e0b3bd102962d752122047f9dfecabee62a261f2af7070e886d64ac5d228f"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: ProfileState.sections: MethodTooLong \u2014 sections runs 268 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 168 over it, 2.68\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":"WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift"},"region":{"startLine":91}}}],"partialFingerprints":{"codehealthFindingId/v1":"0ffe213a9ef20d647242ea3af4b715ff8d59f489b25d9dbfb81e37638816c53b"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: ArticleCollectionViewCell.apply: MethodTooLong \u2014 apply runs 258 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 158 over it, 2.58\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":"Wikipedia/Code/ArticleCollectionViewCell.swift"},"region":{"startLine":2}}}],"partialFingerprints":{"codehealthFindingId/v1":"916bed84db4c367895e73208d0dc9b773586f6aba3ae96ac76d7ae84408f4112"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: WMFHomeDataController: TooManyMethods \u2014 75 methods. The bar is 30 methods; this is 45 over it, 2.50\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":"WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"70b3171f31aa62e177e96625c3eb96b8dc3e00bb37481e4cdd05e8036960b696"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: WMFSourceEditorViewController: TooManyMethods \u2014 73 methods. The bar is 30 methods; this is 43 over it, 2.43\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":"WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorViewController.swift"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"c04fedf038d594d9a0293d45506080895c3e6834accbd4057f2fd873466eabf0"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/ExploreViewController.swift: FileTooLong \u2014 1196 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 696 over it, 2.39\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":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"348ca006c1acf20d438a1175b2f51633d4427b66180c25eb0afe50eb7a2c9673"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: EditorViewController: TooManyMethods \u2014 68 methods. The bar is 30 methods; this is 38 over it, 2.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":"Wikipedia/Code/EditorViewController.swift"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"1570b5efef4b1eb72629993161987007f1febafd7452276115d546959a279fc6"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: WatchlistFunnel: TooManyMethods \u2014 68 methods. The bar is 30 methods; this is 38 over it, 2.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":"Wikipedia/Code/WatchlistFunnel.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"3931c679186ea209d686612c2b0223a20eee3ecc10da2d11868d785700e7f0a1"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: WMFFont.\u0060for\u0060: MethodTooLong \u2014 \u0060for\u0060 runs 211 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 111 over it, 2.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":"WMFComponents/Sources/WMFComponents/Style/WMFFont.swift"},"region":{"startLine":35}}}],"partialFingerprints":{"codehealthFindingId/v1":"4e7def82cc323369a21973c03501821d7e07db96c6378458cabc41d5d748ebf5"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: ArticleViewController: ClassTooLong \u2014 824 significant lines (blank, comment-only and punctuation-only lines excluded), 250 methods. The bar is 400 significant lines; this is 424 over it, 2.06\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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":10}}}],"partialFingerprints":{"codehealthFindingId/v1":"8c5a91c48db3f47a9965b9cb49a2de21a2806153a91e03150a3070753f2392d0"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/ArticleViewController.swift: FileTooLong \u2014 1025 significant lines (blank, comment-only and punctuation-only lines excluded), about 80% of them inside a single declaration: ArticleViewController (11-1444). The bar is 500 significant lines; this is 525 over it, 2.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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"b304cf616fe7d79f8968f63d0cfc256bb905fd5dfa8f4b22b2600f55a27d58fb"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: DiffContainerViewController: TooManyMethods \u2014 61 methods. The bar is 30 methods; this is 31 over it, 2.03\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":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"af4f4367d9b2d1cd64f71d2dd13ca9c9ce3082125bd8847568679e2b6a9b26a7"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: NotificationsCenterViewController: TooManyMethods \u2014 60 methods. The bar is 30 methods; this is 30 over it, 2.00\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":"Wikipedia/Code/NotificationsCenterViewController.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"44a12c8089185b15d6118b7dd014640690abb79f44dfcafb0c484fbc9eafb47e"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: ExploreCardViewController: TooManyMethods \u2014 56 methods. The bar is 30 methods; this is 26 over it, 1.87\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":"Wikipedia/Code/ExploreCardViewController.swift"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"26ff204bb05daa7571a9313847e6171bdab61a72cea3b91527bede250f6ecf47"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: WMFFont.\u0060for\u0060: MethodTooLong \u2014 \u0060for\u0060 runs 186 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 86 over it, 1.86\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":"WMFComponents/Sources/WMFComponents/Style/WMFFont.swift"},"region":{"startLine":61}}}],"partialFingerprints":{"codehealthFindingId/v1":"c3be98f69cc210deddfd6730fc711d070f089477ff06133547aad8f008e4e8f9"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/WMFAppViewController\u002BExtensions.swift: FileTooLong \u2014 912 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 412 over it, 1.82\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":"Wikipedia/Code/WMFAppViewController\u002BExtensions.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"958e66df15d1fbd9d0ed0d075975603e166adf493b5ed2f74dd21a6305c67973"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: ReadingListsSyncOperation: ClassTooLong \u2014 720 significant lines (blank, comment-only and punctuation-only lines excluded), 13 methods. The bar is 400 significant lines; this is 320 over it, 1.80\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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"86df06ecbffe008a815ce74cd8701259f552a400856cc375edde08a7b2ab4459"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: ReadingListsSyncOperation.processLocalUpdates: MethodTooLong \u2014 processLocalUpdates runs 176 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 76 over it, 1.76\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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":479}}}],"partialFingerprints":{"codehealthFindingId/v1":"5a7c69527440a5fa1bb77bf9fdba3eb80213bbae23eb5a41bd8c248cfe5c48f5"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: DonateCoordinator.presentActionSheet: MethodTooLong \u2014 presentActionSheet runs 176 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 76 over it, 1.76\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":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":226}}}],"partialFingerprints":{"codehealthFindingId/v1":"0df73c941ba7cd1096e68f563a3234f76d6322c09f4521253d33b3a4b8be5e17"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/DiffContainerViewController.swift: FileTooLong \u2014 862 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 362 over it, 1.72\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":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"dd4c142173a7e9ce84cd992080d0edfbc6e98e37445e53b3291a43a3de035164"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: MWKDataStore.importViewedArticlesIntoWMFData: MethodTooLong \u2014 importViewedArticlesIntoWMFData runs 171 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 71 over it, 1.71\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":"WMF Framework/MWKDataStore\u002BLanguageVariantMigration.swift"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"aebf24edb6af8fe1f806fb8f4aa00ff187d94be87d02c5e1504e250a056a3a3b"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/TalkPageViewController.swift: FileTooLong \u2014 843 significant lines (blank, comment-only and punctuation-only lines excluded), about 64% of them inside a single declaration: TalkPageViewController (12-971). The bar is 500 significant lines; this is 343 over it, 1.69\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":"Wikipedia/Code/TalkPageViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"a9b34e1831e5f088ee95f5bf9a01cc12ee3ecd28698482566f3667cbce50db49"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: SearchResultsViewController: TooManyMethods \u2014 49 methods. The bar is 30 methods; this is 19 over it, 1.63\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":"Wikipedia/Code/SearchResultsViewController.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"6949d699abddddbb31f6e77ecf61b0c1a505f0597a3e2cc7e84177c0b85a0df6"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: ExploreViewController: ClassTooLong \u2014 646 significant lines (blank, comment-only and punctuation-only lines excluded), 147 methods. The bar is 400 significant lines; this is 246 over it, 1.62\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":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"86014ab9c8c4b8a21d802f1d7818536b7b7c828715f7e4e011d3cdbee7da558e"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: PlacesViewController.regroupArticlesIfNecessary: MethodTooLong \u2014 regroupArticlesIfNecessary runs 161 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 61 over it, 1.61\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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":1449}}}],"partialFingerprints":{"codehealthFindingId/v1":"b35c1f514ba33d6bf4c883802e6685f1119943e5b5c055a48cdeb5495f577dbb"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: ReadingListsViewController: TooManyMethods \u2014 47 methods. The bar is 30 methods; this is 17 over it, 1.57\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":"Wikipedia/Code/ReadingListsViewController.swift"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"87649caf518c16c1d20fcab22d4c9fe90d7f7879fd1688e02f0b116558e33132"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: Session: TooManyMethods \u2014 46 methods. The bar is 30 methods; this is 16 over it, 1.53\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":"Wikipedia/Code/Session.swift"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"c447f5361f11a0da58258261e98b3bfcb9033a72a773fe0447854ff4abd582e4"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: SettingsCoordinator: TooManyMethods \u2014 46 methods. The bar is 30 methods; this is 16 over it, 1.53\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":"Wikipedia/Code/SettingsCoordinator.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"ed1218528375650fbac346e798a58524ab7735a961c4ce3e21d4267c16386a6a"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: ColumnarCollectionViewController: TooManyMethods \u2014 45 methods. The bar is 30 methods; this is 15 over it, 1.50\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":"Wikipedia/Code/ColumnarCollectionViewController.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"9d6e91236549d9397ec8c0ad7736d8a01add256d80932693178f287ef17ae567"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: PageHistoryViewController: 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":"Wikipedia/Code/PageHistoryViewController.swift"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"2cdb49a878a69d0889500380e9dc09a4cebfc77db76e7d7f344cdf5c850bb3da"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: WMF Framework/ReadingListsSyncOperation.swift: FileTooLong \u2014 723 significant lines (blank, comment-only and punctuation-only lines excluded), about 100% of them inside a single declaration: ReadingListsSyncOperation (7-1096). The bar is 500 significant lines; this is 223 over it, 1.45\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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"c798359177ad7c5ccf1cecf5b93c35eee1d1e78fd98fd223c6f0d7a97001f45f"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: WMFActivityTabViewController: TooManyMethods \u2014 43 methods. The bar is 30 methods; this is 13 over it, 1.43\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":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"a35a85e762639d06fda4d324582198604a526d645c623b5be85e8983ab9ddec2"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: ReadingListEntryCollectionViewController: TooManyMethods \u2014 43 methods. The bar is 30 methods; this is 13 over it, 1.43\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":"Wikipedia/Code/ReadingListEntryCollectionViewController.swift"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"a479cde94182bc2eba1e23291093cf8be02e57c19fd70fb868d3413b1bb6e46e"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/EditorViewController.swift: FileTooLong \u2014 715 significant lines (blank, comment-only and punctuation-only lines excluded), about 66% of them inside a single declaration: EditorViewController (14-726). The bar is 500 significant lines; this is 215 over it, 1.43\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":"Wikipedia/Code/EditorViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"6d277c0344a0e7f3265f06a681c7d96710aec6ec400ae6292cef5aad213cec09"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: WMF Framework/Theme.swift: FileTooLong \u2014 708 significant lines (blank, comment-only and punctuation-only lines excluded), about 74% of them inside a single declaration: Colors (95-841). The bar is 500 significant lines; this is 208 over it, 1.42\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":"WMF Framework/Theme.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"91bf9137638184fccc44b6471ff17c490b7d8052248662de6103af5b7d050ff5"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: UIViewController: TooManyMethods \u2014 42 methods. The bar is 30 methods; this is 12 over it, 1.40\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":"Wikipedia/Code/FundraisingAnnouncementPanel.swift"},"region":{"startLine":97}}}],"partialFingerprints":{"codehealthFindingId/v1":"8b2e4dec15481c7cba37ab58ad83621079a9c21cc7917ddd1b9e2e16bcae4790"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: ImageRecommendationsFunnel: TooManyMethods \u2014 42 methods. The bar is 30 methods; this is 12 over it, 1.40\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":"Wikipedia/Code/ImageRecommendationsFunnel.swift"},"region":{"startLine":3}}}],"partialFingerprints":{"codehealthFindingId/v1":"3d53d65155d84bba229a976592254c09ceed220e508d6f887cbd652999981e02"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/DonateCoordinator.swift: FileTooLong \u2014 695 significant lines (blank, comment-only and punctuation-only lines excluded), about 60% of them inside a single declaration: DonateCoordinator (15-631). The bar is 500 significant lines; this is 195 over it, 1.39\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":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"09ed0b6232272d200d2eafdf5822edd3df9d364880872de89594cd0dd6c6b9f6"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: EditInteractionFunnel: TooManyMethods \u2014 41 methods. The bar is 30 methods; this is 11 over it, 1.37\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":"Wikipedia/Code/EditInteractionFunnel.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"6764ac83da7b9585f09d2f9b9eb6c119e25b24ff4dcfe5f4f634913c7d901ef6"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: PageHistoryViewController: ClassTooLong \u2014 542 significant lines (blank, comment-only and punctuation-only lines excluded), 44 methods. The bar is 400 significant lines; this is 142 over it, 1.36\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":"Wikipedia/Code/PageHistoryViewController.swift"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"8b3c768dbcefcb0199456df635ed9c54f03e12caf79a80993d1c96e02e0a5d9f"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: TalkPageViewController: ClassTooLong \u2014 540 significant lines (blank, comment-only and punctuation-only lines excluded), 98 methods. The bar is 400 significant lines; this is 140 over it, 1.35\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":"Wikipedia/Code/TalkPageViewController.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"921c4cd3907d53211cf344035a42a1d0dbc87276aa98c05b4d20dd17dc97699e"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: UserDefaults: TooManyMethods \u2014 40 methods. The bar is 30 methods; this is 10 over it, 1.33\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":"Wikipedia/Code/NSUserDefaults\u002BWMFApplicationDefaults.swift"},"region":{"startLine":35}}}],"partialFingerprints":{"codehealthFindingId/v1":"d5aa853215ba6b762065ff9b1589529942da1ecbe49789d17293d429b355499d"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: CommonStrings: ClassTooLong \u2014 525 significant lines (blank, comment-only and punctuation-only lines excluded), 29 methods. The bar is 400 significant lines; this is 125 over it, 1.31\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":"WMFLocalizations/Sources/WMFNativeLocalizations/CommonStrings.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"dca9cab0e7eb6b96a86d06b70b4e03a1e9f9c37e4558d04c073131fb008290d1"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: Colors: ClassTooLong \u2014 524 significant lines (blank, comment-only and punctuation-only lines excluded), 1 methods. The bar is 400 significant lines; this is 124 over it, 1.31\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":"WMF Framework/Theme.swift"},"region":{"startLine":94}}}],"partialFingerprints":{"codehealthFindingId/v1":"3e84dc3bf2fff10aca3be748f7fd4316c7b22affe18041c13523f3d6f7320738"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: WMFDeveloperSettingsView.body: MethodTooLong \u2014 body runs 131 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 31 over it, 1.31\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":"WMFComponents/Sources/WMFComponents/Components/Developer Settings/WMFDeveloperSettingsView.swift"},"region":{"startLine":13}}}],"partialFingerprints":{"codehealthFindingId/v1":"fa702556d59ca7be9bcaad379ce6c33d91ef6ad71006aa8eeb734cb351c25cbe"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: SettingsCoordinator: ClassTooLong \u2014 522 significant lines (blank, comment-only and punctuation-only lines excluded), 46 methods. The bar is 400 significant lines; this is 122 over it, 1.31\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":"Wikipedia/Code/SettingsCoordinator.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"049190ac6efb8c8305d03a2cdc61c1384f2ce1c50e4954570d3fea712f70c345"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: ReadingListsSyncOperation.executeSync: MethodTooLong \u2014 executeSync runs 129 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 29 over it, 1.29\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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":60}}}],"partialFingerprints":{"codehealthFindingId/v1":"e78b85268167779d54f65adee2c264e2dade2dfcd4290ccf5d6c4c73a93ffc82"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/NotificationsCenterViewController.swift: FileTooLong \u2014 640 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 140 over it, 1.28\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":"Wikipedia/Code/NotificationsCenterViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"488d335b69b7c5a1a2e4653c31844f42ab389d61c72fa70c4ff9ae26f32822c4"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: WMFAccountLoginLogoutFetcher.login: MethodTooLong \u2014 login runs 127 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 27 over it, 1.27\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":"Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift"},"region":{"startLine":89}}}],"partialFingerprints":{"codehealthFindingId/v1":"17d56f57191e0c94a949ac7ffd1a1e614e2af24a9311979f3ff3fd3d1d5d34bb"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: WMFAccountCreationViewController: TooManyMethods \u2014 37 methods. The bar is 30 methods; this is 7 over it, 1.23\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":"Wikipedia/Code/WMFAccountCreationViewController.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"c2644c03c137d2c45b1390cfe18e2876c03050e124813cb13c6ac614973fc6f0"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: WMFActivityTabHostingController: ClassTooLong \u2014 491 significant lines (blank, comment-only and punctuation-only lines excluded), 0 methods. The bar is 400 significant lines; this is 91 over it, 1.23\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":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":10}}}],"partialFingerprints":{"codehealthFindingId/v1":"d1069ef03974e68cf24f6c07ebd93a239d8f2e3ac61c417b8829882099117dad"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/PageHistoryViewController.swift: FileTooLong \u2014 607 significant lines (blank, comment-only and punctuation-only lines excluded), about 89% of them inside a single declaration: PageHistoryViewController (21-826). The bar is 500 significant lines; this is 107 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":"Wikipedia/Code/PageHistoryViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"ac86542fcf240458cf283b92365836c37d9a1b366ca0cf265d37685d09c3b4a2"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: SavedViewController: TooManyMethods \u2014 36 methods. The bar is 30 methods; this is 6 over it, 1.20\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":"Wikipedia/Code/SavedViewController.swift"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"0c322ea5c067ef41a7b2c9901928f788d7d7521f11dcaec3d5d8bb0ef8895a44"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: TalkPageTopicComposeViewController: TooManyMethods \u2014 36 methods. The bar is 30 methods; this is 6 over it, 1.20\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":"Wikipedia/Code/TalkPageTopicComposeViewController.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"dff5cbb02457c9939482834fe5a1490719d8c61c2455a4f4ace59aff3dd97f00"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: WMFLoginViewController: TooManyMethods \u2014 36 methods. The bar is 30 methods; this is 6 over it, 1.20\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":"Wikipedia/Code/WMFLoginViewController.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"4e2861b4cddd069c06d4bc8f0866ba4b89690ceb8c2dca94f0ca059fadb827b6"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: WMFAppViewController.viewDidLoad: MethodTooLong \u2014 viewDidLoad runs 119 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 19 over it, 1.19\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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"7ba5195d200a2afa5980ebc8cce1cf6ae06c3b5ab00300909d4d4acf1be4577e"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Home/WMFForYouView.swift: FileTooLong \u2014 593 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 93 over it, 1.19\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":"WMFComponents/Sources/WMFComponents/Components/Home/WMFForYouView.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"342804b57f7bd54178fb2fef32ffd98eababa8eabb1166f1f0fb1c4cbe23c33e"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: EditorViewController: ClassTooLong \u2014 474 significant lines (blank, comment-only and punctuation-only lines excluded), 68 methods. The bar is 400 significant lines; this is 74 over it, 1.19\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":"Wikipedia/Code/EditorViewController.swift"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"2be24ca574130cc7b6dd551a05c581eac4fc6a4f4f2bae43c4882637f04cb23c"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: WMFNavigationBarConfiguring.configureNavigationBar: MethodTooLong \u2014 configureNavigationBar runs 118 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 18 over it, 1.18\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":"WMFComponents/Sources/WMFComponents/Extensions/Navigation Bar/WMFNavigationBarConfiguring.swift"},"region":{"startLine":119}}}],"partialFingerprints":{"codehealthFindingId/v1":"92231fff1f75658d34dd214f925ae005f9f31558b23f452bc08ad8b03e498b20"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: WMFNativeLocalizations/CommonStrings.swift: FileTooLong \u2014 588 significant lines (blank, comment-only and punctuation-only lines excluded), about 89% of them inside a single declaration: CommonStrings (8-860). The bar is 500 significant lines; this is 88 over it, 1.18\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":"WMFLocalizations/Sources/WMFNativeLocalizations/CommonStrings.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"e05b487e0ccf51782dc232455ff64301b9fc3638e6fa020c1f10c40d0661a15d"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/ActivityTabViewController.swift: FileTooLong \u2014 585 significant lines (blank, comment-only and punctuation-only lines excluded), about 84% of them inside a single declaration: WMFActivityTabHostingController (10-800). The bar is 500 significant lines; this is 85 over it, 1.17\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":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"ce36a27f11ab2504e0d2d450292bd460475309a7873f75518a1503a9ce58573c"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: PermanentlyPersistableURLCache: TooManyMethods \u2014 35 methods. The bar is 30 methods; this is 5 over it, 1.17\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":"WMF Framework/PermanentlyPersistableURLCache.swift"},"region":{"startLine":23}}}],"partialFingerprints":{"codehealthFindingId/v1":"f5b55ff06d8bc8208ca2dfb8af69d328948981c03474155e472af12f69c3ed16"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: HomeViewController: TooManyMethods \u2014 35 methods. The bar is 30 methods; this is 5 over it, 1.17\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":"Wikipedia/Code/HomeViewController.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"e9ce47599774eb7688f3a00510d0e9c3c217886f8210f75981a6365b1857f6af"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: EditSaveViewController: ClassTooLong \u2014 463 significant lines (blank, comment-only and punctuation-only lines excluded), 34 methods. The bar is 400 significant lines; this is 63 over it, 1.16\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":"Wikipedia/Code/EditSaveViewController.swift"},"region":{"startLine":50}}}],"partialFingerprints":{"codehealthFindingId/v1":"45aafa4c282e4b88644f555569298866153f90d852527d74e3a83932b965061a"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: EditSaveViewController: TooManyMethods \u2014 34 methods. The bar is 30 methods; this is 4 over it, 1.13\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":"Wikipedia/Code/EditSaveViewController.swift"},"region":{"startLine":50}}}],"partialFingerprints":{"codehealthFindingId/v1":"a31cf41db844d3ee401c8f8c259f45afcc39be3e5e946f6605a6b4034f88361a"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: ReadingListsFunnel: TooManyMethods \u2014 34 methods. The bar is 30 methods; this is 4 over it, 1.13\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":"Wikipedia/Code/ReadingListsFunnel.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"4b9a23a35f57ba4fab26798e3257ec3b79b571764690ee4872b9b0abeabf6c24"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/ReadingListsController.swift: FileTooLong \u2014 566 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 66 over it, 1.13\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":"Wikipedia/Code/ReadingListsController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"7ce2270276401f07d3d42ca725a89c211698d13055cb0e8984b3480c91d2f4e2"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/SettingsCoordinator.swift: FileTooLong \u2014 553 significant lines (blank, comment-only and punctuation-only lines excluded), about 94% of them inside a single declaration: SettingsCoordinator (13-863). The bar is 500 significant lines; this is 53 over it, 1.11\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":"Wikipedia/Code/SettingsCoordinator.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"c42bb43cf416d887e20b6c50823535dc295899e78ad4a77904b57a7b4f5614e1"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: DonateCoordinator: TooManyMethods \u2014 33 methods. The bar is 30 methods; this is 3 over it, 1.10\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":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"2a14fade2f5408961ce94c2efc0c145e36280870cd4c33d8c5becd3b2d68ba8f"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: InsertMediaSettingsViewController: TooManyMethods \u2014 33 methods. The bar is 30 methods; this is 3 over it, 1.10\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":"Wikipedia/Code/InsertMediaSettingsViewController.swift"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"e0e530224de3d3579e6634a141ca5c4afd2cade10cb963de6527588381381d7b"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Code/ExploreCardViewController.swift: FileTooLong \u2014 546 significant lines (blank, comment-only and punctuation-only lines excluded), about 71% of them inside a single declaration: ExploreCardViewController (24-594). The bar is 500 significant lines; this is 46 over it, 1.09\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":"Wikipedia/Code/ExploreCardViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"e3c8c8e5f827eb832d7a0ee07330e87b27d53bec87c34443d431a25636857069"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: HtmlUtils: ClassTooLong \u2014 431 significant lines (blank, comment-only and punctuation-only lines excluded), 31 methods. The bar is 400 significant lines; this is 31 over it, 1.08\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":"WMFComponents/Sources/WMFComponents/Utility/HTMLUtils.swift"},"region":{"startLine":5}}}],"partialFingerprints":{"codehealthFindingId/v1":"5d61ca30222f220abeb684880dcc627ce871418e6d42e9a46495b2c4e134a584"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: WMFSFSymbolIcon: ClassTooLong \u2014 429 significant lines (blank, comment-only and punctuation-only lines excluded), 1 methods. The bar is 400 significant lines; this is 29 over it, 1.07\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":"WMFComponents/Sources/WMFComponents/Style/WMFIcon.swift"},"region":{"startLine":55}}}],"partialFingerprints":{"codehealthFindingId/v1":"7b5fc1d3b65ab880b93ff448effb812a189f3f35dfc84a4cb742a3a240b41846"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: DetailTransition.animateTransition: MethodTooLong \u2014 animateTransition runs 107 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 7 over it, 1.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":"Wikipedia/Code/DetailTransition.swift"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"8ac8cf03afe01f60b2273eb3eaa6b56a15773d07f4acc240fdfb1af190913a20"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Article Tabs/WMFArticleTabsDataController.swift: FileTooLong \u2014 531 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 31 over it, 1.06\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":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"fa1d52152e284cb843cc4b9b59cd3b659379ae57455c4452b7a73a63daa69744"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: ArticlePlaceView.setup: MethodTooLong \u2014 setup runs 106 significant lines (blank, comment-only and punctuation-only lines excluded) 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":"Wikipedia/Code/ArticlePlaceView.swift"},"region":{"startLine":61}}}],"partialFingerprints":{"codehealthFindingId/v1":"d49d21ac140e559195b23e6ee22e4ec2820b415fcc48a5290850bd55e50c7ce2"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Home/WMFHomeDataController.swift: FileTooLong \u2014 528 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 28 over it, 1.06\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":"WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"d85734b6149da3f09af2e5c12b160d022c0cc47fa0c44a64dcaacbe6aabc7142"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: ReadingListsSyncOperation.locallyCreate: MethodTooLong \u2014 locallyCreate runs 104 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 4 over it, 1.04\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":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":756}}}],"partialFingerprints":{"codehealthFindingId/v1":"aa9b852d675da3bc2e36b9380d177fcceedf852ba93b58bd422657d092f85f44"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: DonateCoordinator: ClassTooLong \u2014 415 significant lines (blank, comment-only and punctuation-only lines excluded), 33 methods. The bar is 400 significant lines; this is 15 over it, 1.04\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":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"2aa1e8952bc8e76d8e32f9bbe1acaf04c05fc45b91317073a66a689891f8e2b6"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: HtmlUtils: TooManyMethods \u2014 31 methods. The bar is 30 methods; this is 1 over it, 1.03\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":"WMFComponents/Sources/WMFComponents/Utility/HTMLUtils.swift"},"region":{"startLine":5}}}],"partialFingerprints":{"codehealthFindingId/v1":"5f30e084379678767f81fd1d4a400756c1fa79f9a3b691c8e1f5071296b61078"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: WMFArticleTabsDataController: TooManyMethods \u2014 31 methods. The bar is 30 methods; this is 1 over it, 1.03\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":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"d0cc0ed7c6c02f30aa937f955c841afc9cd390a0ea853968a7e03d924a2e3d78"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: AppOnboardingCoordinator.start: MethodTooLong \u2014 start runs 103 significant lines (blank, comment-only and punctuation-only lines excluded) 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":"Wikipedia/Code/AppOnboardingCoordinator.swift"},"region":{"startLine":33}}}],"partialFingerprints":{"codehealthFindingId/v1":"c4cc14969803c90ded2c6607962b45c0c6d51a99eaa0ab09e769ba927b70f204"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: WMFAccountCreationViewController: ClassTooLong \u2014 408 significant lines (blank, comment-only and punctuation-only lines excluded), 37 methods. The bar is 400 significant lines; this is 8 over it, 1.02\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":"Wikipedia/Code/WMFAccountCreationViewController.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"c4f90dd5d23de7c2762b19c4150192ce9cb78b721500b8cf86b86e36e966bfdb"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: WMFContentGroup.detailViewControllerForPreviewItemAtIndex: MethodTooLong \u2014 detailViewControllerForPreviewItemAtIndex runs 102 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 2 over it, 1.02\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":"WMF Framework/WMFContentGroup\u002BDisplay.swift"},"region":{"startLine":13}}}],"partialFingerprints":{"codehealthFindingId/v1":"79687869dda4e0ec0a9b153335edec1054b7f355cb75d5410f654c2a0bf31ad0"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: NotificationsCenterCell.setup: MethodTooLong \u2014 setup runs 102 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 2 over it, 1.02\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":"Wikipedia/Code/NotificationsCenterCell.swift"},"region":{"startLine":312}}}],"partialFingerprints":{"codehealthFindingId/v1":"cb9ae73bacd4649d5165de0607cfcf035c092bad26e97764b2fe440656586023"}},{"ruleId":"D3","level":"warning","message":{"text":"ClassTooLong: WMFActivityTabView: ClassTooLong \u2014 402 significant lines (blank, comment-only and punctuation-only lines excluded), 12 methods. The bar is 400 significant lines; this is 2 over it, 1.01\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":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"19419c15310f1ff66f03a9a0c630cbcb4e215508fe7be5deff7b3a409681d4e0"}},{"ruleId":"D4","level":"warning","message":{"text":"Near-duplicate member family (4 members, 12 shared lines): WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift:54-68 | WMFComponents/Sources/WMFComponents/Components/Saved/All Articles/WMFSavedAllArticlesViewModel.swift:33-47 | WMFComponents/Sources/WMFComponents/Components/Settings/WMFSettingsViewModel.swift:92-142 | WMFComponents/Sources/WMFComponents/Components/Watchlist/Filter/WMFWatchlistFilterViewModel.swift:38-66 \u2014 These 4 members are variants of one another: a block of 12 lines reported below appears in every one of them, and the pairwise near-duplicate rows they would otherwise produce are collapsed into this row. Read them as one construct written 4 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 4 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift"},"region":{"startLine":54}}}],"partialFingerprints":{"codehealthFindingId/v1":"1e8ddb601359b072f73c8f22b4e258c6874f9176a96eb61b77bc92d31d069079"}},{"ruleId":"D4","level":"warning","message":{"text":"Near-duplicate member pair (22 shared lines): WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsViewModel.swift:51-100 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/WMFHomeFeedForYouSettingsViewModel.swift:46-77 \u2014 These two members are variants of one another: 22 of their lines are already reported as duplicated blocks below, spread through both bodies rather than gathered into one. Read them as a single construct written twice. The repair is at the members\u0027 grain \u2014 factor the shared pipeline into one implementation the two call with their differences as parameters or as an injected step, or, where the difference is systematic (sync against async, one transport against another), generate one from the other. Extracting the individual blocks below is not the same fix: it leaves the two bodies in place and the next edit still has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsViewModel.swift"},"region":{"startLine":51}}}],"partialFingerprints":{"codehealthFindingId/v1":"c8790e5348acc54f25f45b9a67d66e4e257e6eb0bcbea0333fa1fab8b8262cee"}},{"ruleId":"D4","level":"warning","message":{"text":"Edited copy of a member (22 corresponding lines): Wikipedia/Code/TalkPageTopicComposeViewController\u002BTalkPageFormattingToolbar.swift:16-41 | Wikipedia/Code/TalkPageViewController\u002BTalkPageFormattingToolbar.swift:19-45 \u2014 These two members are one piece of code written twice and then edited apart: 22 consecutive lines correspond almost exactly, broken only by small local edits. Most of that correspondence is NOT reported as duplicated blocks below \u2014 the edits cut it into fragments and only the largest of them clear the block floor, so the rows below understate it. The repair is at the members\u0027 grain \u2014 factor the shared implementation into one the two call with their differences as parameters or as an injected step, or, where the difference is systematic (an extra return value, one transport against another), generate one from the other. Left alone, the next edit has to be made twice and the two will drift further apart."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageTopicComposeViewController\u002BTalkPageFormattingToolbar.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"fbb8c08e285dd820bf1c603e448b6c0b47361b0696da6e4a7d7f83bf0e068517"}},{"ruleId":"D4","level":"warning","message":{"text":"Edited copy of a member (24 corresponding lines): WMFComponents/Sources/WMFComponents/Components/Settings/Push Notifications/WMFPushNotificationsSettingsView.swift:56-79 | WMFComponents/Sources/WMFComponents/Components/Settings/Storage and Syncing/WMFStorageAndSyncingSettingsView.swift:51-74 \u2014 These two members are one piece of code written twice and then edited apart: 24 consecutive lines correspond almost exactly, broken only by small local edits. Most of that correspondence is NOT reported as duplicated blocks below \u2014 the edits cut it into fragments and only the largest of them clear the block floor, so the rows below understate it. The repair is at the members\u0027 grain \u2014 factor the shared implementation into one the two call with their differences as parameters or as an injected step, or, where the difference is systematic (an extra return value, one transport against another), generate one from the other. Left alone, the next edit has to be made twice and the two will drift further apart."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Push Notifications/WMFPushNotificationsSettingsView.swift"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"8422b97cc630cd85d84166e533b984fa6bd3d43ab1bda5b4a64dfd1bb1bca6f7"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (10 members, 50\u002B identical tokens): Wikipedia/Code/DiffContainerViewController.swift:998-1011 | Wikipedia/Code/NotificationsCenterViewController.swift:593-631 | Wikipedia/Code/ReadingListsAlertController.swift:95-123 | Wikipedia/Code/ThanksGiving.swift:35-140 | Wikipedia/Code/UIViewController\u002BExtensions.swift:81-126 | Wikipedia/Code/UIViewController\u002BExtensions.swift:136-156 | Wikipedia/Code/UIViewController\u002BExtensions.swift:171-185 | Wikipedia/Code/UIViewController\u002BExtensions.swift:187-206 | Wikipedia/Code/UIViewController\u002BExtensions.swift:208-227 | Wikipedia/Code/UIViewController\u002BExtensions.swift:229-242 \u2014 These 10 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 10 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 10 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":998}}}],"partialFingerprints":{"codehealthFindingId/v1":"b38ad0efcce032068d1d8a5d0f546803bbb00c6d43d01f3281f6ee97b448ef5b"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (9 members, 50\u002B identical tokens): WMF Framework/Remote Notifications/RemoteNotificationsController.swift:562-624 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/Main/WMFHomeFeedSettingsViewModel.swift:12-38 | Wikipedia/Code/ArticleViewController\u002BDonationReminder.swift:197-250 | Wikipedia/Code/DiffListChangeItemViewModel.swift:229-300 | Wikipedia/Code/DonateCoordinator.swift:461-574 | Wikipedia/Code/FindAndReplaceKeyboardBar.swift:344-378 | Wikipedia/Code/NotificationsCenterViewController.swift:555-591 | Wikipedia/Code/WMFAppViewController\u002BExtensions.swift:1038-1247 | Wikipedia/Code/WatchlistController.swift:127-221 \u2014 These 9 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 9 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 9 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Remote Notifications/RemoteNotificationsController.swift"},"region":{"startLine":562}}}],"partialFingerprints":{"codehealthFindingId/v1":"89ad46884015ae63cdbe4205a02abf974a505286fc5ee0e9e0423f1d6fb33836"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (8 members, 50\u002B identical tokens): WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift:16-47 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsView.swift:14-39 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/WMFHomeFeedForYouSettingsView.swift:14-36 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/WMFHomeFeedWhatsDrivingSettingsView.swift:14-44 | WMFComponents/Sources/WMFComponents/Components/Settings/Push Notifications/WMFPushNotificationsSettingsView.swift:16-52 | WMFComponents/Sources/WMFComponents/Components/Settings/Search/WMFSearchSettingsView.swift:16-47 | WMFComponents/Sources/WMFComponents/Components/Settings/Storage and Syncing/WMFStorageAndSyncingSettingsView.swift:16-47 | WMFComponents/Sources/WMFComponents/Components/Settings/Year In Review/WMFYearInReviewSettingsView.swift:16-47 \u2014 These 8 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 8 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 8 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"3adabce55efc0715ac7537d109f3b18f6d937b7b1229518dc44851ef74e8cd1b"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (6 members, 50\u002B identical tokens): WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift:63-94 | WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift:96-120 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFCategoriesDataController.swift:22-60 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFPageTopicsDataController.swift:26-71 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFPageTopicsDataController.swift:246-268 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFPageViewsDataController.swift:246-267 \u2014 These 6 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 6 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 6 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift"},"region":{"startLine":63}}}],"partialFingerprints":{"codehealthFindingId/v1":"c75982e7f33bec16741111fefee09d1a19f366e61f32b40ba45085c5fac30f1c"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (6 members, 50\u002B identical tokens): Wikipedia/Code/ActivityTabFunnel.swift:62-78 | Wikipedia/Code/ArticleTabsFunnel.swift:65-81 | Wikipedia/Code/DonateFunnel.swift:115-133 | Wikipedia/Code/EditInteractionFunnel.swift:78-96 | Wikipedia/Code/ImageRecommendationsFunnel.swift:83-101 | Wikipedia/Code/SearchFunnel.swift:44-63 \u2014 These 6 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 6 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 6 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ActivityTabFunnel.swift"},"region":{"startLine":62}}}],"partialFingerprints":{"codehealthFindingId/v1":"946f8a6af63b89a909a8e90e15248643965b5322c58715c854d9c3c5f2e66429"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (4 members, 50\u002B identical tokens): WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:327-364 | WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:368-405 | WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:409-448 | WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:452-505 \u2014 These 4 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 4 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 4 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift"},"region":{"startLine":327}}}],"partialFingerprints":{"codehealthFindingId/v1":"63eda99d57cc953759c14bbd88709795cb14fc6275a9b956f4c122835fd241ac"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (4 members, 50\u002B identical tokens): Wikipedia/Code/ArticleLocationCollectionViewController.swift:217-231 | Wikipedia/Code/ColumnarCollectionViewController.swift:506-520 | Wikipedia/Code/NewsViewController.swift:257-271 | Wikipedia/Code/OnThisDayViewController.swift:262-276 \u2014 These 4 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 4 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 4 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleLocationCollectionViewController.swift"},"region":{"startLine":217}}}],"partialFingerprints":{"codehealthFindingId/v1":"e978f628329850b0ec401b2b899c55f5ded7cf9d8298a4821d8d07973d9c6f5a"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (4 members, 50\u002B identical tokens): Wikipedia/Code/WMFAuthAccountCreationInfoFetcher.swift:22-49 | Wikipedia/Code/WMFAuthLoginInfoFetcher.swift:22-50 | Wikipedia/Code/WMFCaptchaResetter.swift:21-44 | Wikipedia/Code/WMFCurrentUserFetcher.swift:58-100 \u2014 These 4 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 4 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 4 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAuthAccountCreationInfoFetcher.swift"},"region":{"startLine":22}}}],"partialFingerprints":{"codehealthFindingId/v1":"30dfc042674977336cdfc051341e95d92e25391db0e56f8d44f4b0b0da50eb85"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (48\u201349 lines \u00D7 2): Wikipedia/Code/TempAccountSheetCoordinator.swift:72-119 | Wikipedia/Code/TempAccountSheetCoordinator.swift:138-186 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/TempAccountSheetCoordinator.swift:72\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TempAccountSheetCoordinator.swift"},"region":{"startLine":72}}}],"partialFingerprints":{"codehealthFindingId/v1":"3a340e791e92b5b4f269c39e413e96f06be50be9082872ea7ca59747ae8a5252"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (43\u201344 lines \u00D7 3): WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift:164-207 | WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift:293-335 | WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift:383-426 \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":"WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift"},"region":{"startLine":164}}}],"partialFingerprints":{"codehealthFindingId/v1":"f0fe83070570ef4535c9e1edfa13809cf951efc5ca3c973495d043ab98a03e18"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (42 lines \u00D7 2): Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift:18-59 | Wikipedia/Code/NotificationsCenterDetailViewModel\u002BActionExtensions.swift:82-123 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift:18\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift"},"region":{"startLine":18}}}],"partialFingerprints":{"codehealthFindingId/v1":"196ce21530b6644530a57494cc66217a8cc30e745d28afd9c85cdf724679c874"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (38\u201339 lines \u00D7 2): WMFData/Sources/WMFData/Service/WMFBasicService.swift:109-146 | WMFData/Sources/WMFData/Service/WMFBasicService.swift:182-220 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Service/WMFBasicService.swift:109\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Service/WMFBasicService.swift"},"region":{"startLine":109}}}],"partialFingerprints":{"codehealthFindingId/v1":"d67553fc49942b9762c9a1c89e6dcdd725a2b9e0ea43caa76367b87a6a9805ab"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (33 lines \u00D7 2): Wikipedia/Code/ArticleViewController.swift:592-624 | Wikipedia/Code/ExploreViewController.swift:1141-1173 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ArticleViewController.swift:592\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":592}}}],"partialFingerprints":{"codehealthFindingId/v1":"3812573bc1748fb2f2a5b5e4d27fbb34e5cb9ff884fc3f2cf5b833868c4b5192"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (29 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Reading Challenge Widget/WMFRandomWidgetView.swift:73-101 | WMFComponents/Sources/WMFComponents/Components/Reading Challenge Widget/WMFRandomWidgetView.swift:110-138 \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. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060WMFComponents/Sources/WMFComponents/Components/Reading Challenge Widget/WMFRandomWidgetView.swift:108\u0060 calls \u0060min\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Reading Challenge Widget/WMFRandomWidgetView.swift:72\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Reading Challenge Widget/WMFRandomWidgetView.swift"},"region":{"startLine":73}}}],"partialFingerprints":{"codehealthFindingId/v1":"db41015a553c421ea92ef9f684a80147101523c6b1fe05283eb017c3e82cb920"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (26\u201327 lines \u00D7 2): Wikipedia/Code/Session.swift:460-485 | Wikipedia/Code/Session.swift:491-517 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/Session.swift:460\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/Session.swift"},"region":{"startLine":460}}}],"partialFingerprints":{"codehealthFindingId/v1":"bcf16530880e2dbc5f2952b0b5e596946cc06ad2bb496bad4f15030e85ca74f3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (24\u201326 lines \u00D7 2): Wikipedia/Code/DiffContainerViewController.swift:940-963 | Wikipedia/Code/DiffContainerViewController.swift:966-991 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffContainerViewController.swift:940\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":940}}}],"partialFingerprints":{"codehealthFindingId/v1":"533a8a01b90871f7ca9ec3ad431d8cbd59fec48f28f193c124629206ab3aae83"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (25 lines \u00D7 5): WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift:19-43 | WMFComponents/Sources/WMFComponents/Components/Settings/Push Notifications/WMFPushNotificationsSettingsView.swift:19-43 | WMFComponents/Sources/WMFComponents/Components/Settings/Search/WMFSearchSettingsView.swift:19-43 | WMFComponents/Sources/WMFComponents/Components/Settings/Storage and Syncing/WMFStorageAndSyncingSettingsView.swift:19-43 | WMFComponents/Sources/WMFComponents/Components/Settings/Year In Review/WMFYearInReviewSettingsView.swift:19-43 \u2014 before extracting anything, compare \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Push Notifications/WMFPushNotificationsSettingsView.swift\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 69 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. The two sit in different directories, so one cannot simply be deleted in favour of the other while both are reached separately: hoist the shared part into a location both already depend on and have each file call it, and retire whichever file turns out to have no caller of its own left. Extracting one helper per block leaves the fork in place. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift:19\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060viewModel\u0060 to \u0060WMFAccountSettingsViewModel\u0060 in one and \u0060WMFPushNotificationsSettingsViewModel\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift"},"region":{"startLine":19}}}],"partialFingerprints":{"codehealthFindingId/v1":"bc93f2d0ecc67fefd35fded6d1adba9e63071b1cacb87a53580294fe3ce292b2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (23\u201325 lines \u00D7 2): Wikipedia/Code/DescriptionWelcomePageViewController.swift:76-100 | Wikipedia/Code/WMFWelcomePageViewController.swift:86-108 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DescriptionWelcomePageViewController.swift\u0060 and \u0060Wikipedia/Code/WMFWelcomePageViewController.swift\u0060 as WHOLE FILES: this scan already matched 9 separate duplicated blocks between them, totalling at least 84 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":"Wikipedia/Code/DescriptionWelcomePageViewController.swift"},"region":{"startLine":76}}}],"partialFingerprints":{"codehealthFindingId/v1":"0f714a70309dcb9758fcfe82b53c0d7cf25613178252ddab52d5762fa09e2a42"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (25 lines \u00D7 2): Wikipedia/Code/SettingsCoordinator.swift:84-108 | Wikipedia/Code/WMFAppViewController\u002BExtensions.swift:1343-1367 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAppViewController\u002BExtensions.swift:1343\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/SettingsCoordinator.swift"},"region":{"startLine":84}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c232d6d68d2452979ec3c2e4d793a744b9181d1715a7b35e1c9d9c08dad5709"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (24 lines \u00D7 2): WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:341-364 | WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:382-405 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:341\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift"},"region":{"startLine":341}}}],"partialFingerprints":{"codehealthFindingId/v1":"d0f335a3831b21bd9098a21a149e7cac2e0d9b7fe4fc92bc6324fce52c662b50"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (24 lines \u00D7 2): Wikipedia/Code/CollectionViewCell.swift:163-186 | Wikipedia/Code/SizeThatFitsReusableView.swift:84-107 \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":"Wikipedia/Code/CollectionViewCell.swift"},"region":{"startLine":163}}}],"partialFingerprints":{"codehealthFindingId/v1":"da0e3699c5408893dadecdc8596fc6f0c42c105f4c0e24191c107defe0ead779"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (24 lines \u00D7 2): WMF Framework/Remote Notifications/Model/RemoteNotificationFilterType.swift:257-280 | WMF Framework/Remote Notifications/Model/RemoteNotificationType.swift:85-108 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/Remote Notifications/Model/RemoteNotificationFilterType.swift:257\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Remote Notifications/Model/RemoteNotificationFilterType.swift"},"region":{"startLine":257}}}],"partialFingerprints":{"codehealthFindingId/v1":"f0e67236e4024b36c6e12d39dc158bcc0f79edb27eb661060def318ca186357a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (22\u201323 lines \u00D7 2): Wikipedia/Code/TalkPageCoffeeRollViewController.swift:64-85 | Wikipedia/Code/TalkPageViewController.swift:1370-1392 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/TalkPageCoffeeRollViewController.swift:64\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageCoffeeRollViewController.swift"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"27ef96f399c98e462a3513599077a147e11fdd5c22eb2c5e1d111deab6852bef"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (22\u201323 lines \u00D7 2): Wikipedia/Code/Controllers/ShortDescriptionController.swift:166-188 | Wikipedia/Code/Controllers/ShortDescriptionController.swift:208-229 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/Controllers/ShortDescriptionController.swift:166\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/Controllers/ShortDescriptionController.swift"},"region":{"startLine":166}}}],"partialFingerprints":{"codehealthFindingId/v1":"71e7ebf6696b312b3549aa4b8aa7dd1144611059c10a62f600e80559312b4d7f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (22 lines \u00D7 2): Wikipedia/Code/EditSaveViewController.swift:263-284 | Wikipedia/Code/EditSaveViewController.swift:297-318 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/EditSaveViewController.swift:263\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/EditSaveViewController.swift"},"region":{"startLine":263}}}],"partialFingerprints":{"codehealthFindingId/v1":"ffc13600baa65dc21fdff65399bf9b8df06bb598c9af356e6b160837be1d1ad2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11\u201321 lines \u00D7 3): WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorAccessibilityIdentifiers.swift:7-17 | WMFComponents/Sources/WMFComponents/Components/Search/Results/WMFSearchResultsViewModel.swift:18-38 | WMFComponents/Sources/WMFComponents/Components/Suggested Edits/Image Recommendations/WMFImageRecommendationsViewModel.swift:31-41 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 3 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 3 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorAccessibilityIdentifiers.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"23d08b176a0da3593361e66042b7a996e654cd292886c7f045e9b879a48240b3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (21 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:54-74 | WMFComponents/Sources/WMFComponents/Components/Settings/WMFSettingsViewModel.swift:106-126 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:54\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift"},"region":{"startLine":54}}}],"partialFingerprints":{"codehealthFindingId/v1":"cd259d6920c9a055e5e596a62c54f2a1832a7232c8b5aba6362b89e7fa46c9a2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (20\u201321 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstView.swift:163-182 | WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstView.swift:197-217 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstView.swift:163\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstView.swift"},"region":{"startLine":163}}}],"partialFingerprints":{"codehealthFindingId/v1":"ab1ba502f3c071f671cb1d4018d69e85e5b6143120594759fe377fa595c39d3b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (20\u201321 lines \u00D7 2): WMF Framework/ArticleCacheController.swift:53-73 | WMF Framework/ArticleCacheController.swift:91-110 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/ArticleCacheController.swift:53\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also register a scope-exit action (a \u0060defer\u0060-style statement) that runs when the function holding them returns: moved into a called unit it would run when THAT unit returns instead \u2014 before the caller uses what it releases \u2014 so keep the registration at the call site and extract only the work around it, or have the extracted unit hand the resource back for the caller to register."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/ArticleCacheController.swift"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"c7490d30c96a5e3ac718fc91ef8053e91e079441f03a7b9cbcbd7af76eea780c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (21 lines \u00D7 2): Wikipedia/Code/DiffFetcher.swift:146-166 | Wikipedia/Code/DiffFetcher.swift:205-225 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffFetcher.swift:146\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping ((Result\u003CWMFPageHistoryRevision, Error\u003E) -\u003E Void)\u0060 in one and \u0060@escaping (Result\u003CWMFPageHistoryRevision, Error\u003E) -\u003E Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffFetcher.swift"},"region":{"startLine":146}}}],"partialFingerprints":{"codehealthFindingId/v1":"69907807fce2df36b56687435cd380857b0fc64c5a649eb4f80014a3ea67905b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (20\u201321 lines \u00D7 2): Wikipedia/Code/ArticleViewController\u002BEditing.swift:162-182 | Wikipedia/Code/ArticleViewController\u002BEditing.swift:216-235 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ArticleViewController\u002BEditing.swift:162\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleViewController\u002BEditing.swift"},"region":{"startLine":162}}}],"partialFingerprints":{"codehealthFindingId/v1":"835e99ae580edb699ddb36ae9878bc71d2bdf60688944cf1fb04207fd392692e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (20\u201321 lines \u00D7 2): Wikipedia/Code/TalkPageTopicComposeViewController\u002BTalkPageFormattingToolbar.swift:22-41 | Wikipedia/Code/TalkPageViewController\u002BTalkPageFormattingToolbar.swift:25-45 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/TalkPageTopicComposeViewController\u002BTalkPageFormattingToolbar.swift:22\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageTopicComposeViewController\u002BTalkPageFormattingToolbar.swift"},"region":{"startLine":22}}}],"partialFingerprints":{"codehealthFindingId/v1":"9797276dcf598867bfe741937d629cfd31ef407a32658db3e24b22452f2d790b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15\u201320 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Settings/WMFSettingsViewController.swift:42-56 | Wikipedia/Code/Database Population/DatabasePopulationHostingController.swift:26-45 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Settings/WMFSettingsViewController.swift:42\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/WMFSettingsViewController.swift"},"region":{"startLine":42}}}],"partialFingerprints":{"codehealthFindingId/v1":"e523333eb131b5fbda06add542c3c99b04702fa01d91130fc33f508b11236a7c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (20 lines \u00D7 2): WMF Framework/CacheController.swift:151-170 | WMF Framework/ImageCacheController.swift:14-33 \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. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/CacheController.swift"},"region":{"startLine":151}}}],"partialFingerprints":{"codehealthFindingId/v1":"2fe021eb12cbbdcbe07d5278947bb4de63fc346be00f6d14a21f952d8eae2e87"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19\u201320 lines \u00D7 2): WMF Framework/Remote Notifications/RemoteNotificationsAPIController.swift:297-316 | WMF Framework/Remote Notifications/RemoteNotificationsAPIController.swift:325-343 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/Remote Notifications/RemoteNotificationsAPIController.swift:297\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Remote Notifications/RemoteNotificationsAPIController.swift"},"region":{"startLine":297}}}],"partialFingerprints":{"codehealthFindingId/v1":"63648dd8e1e88c7ffad84afef84c81aaa809a95065cd453d9dcead2f5f680485"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (20 lines \u00D7 2): Wikipedia/Code/DiffContainerViewController.swift:1346-1365 | Wikipedia/Code/WatchlistController.swift:288-307 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffContainerViewController.swift:1346\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":1346}}}],"partialFingerprints":{"codehealthFindingId/v1":"371f422d2f084fe7a1b9349a9b6e7d54fd26714a65f9a3840d3554e5685702c4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19\u201320 lines \u00D7 2): Wikipedia/Code/NewsViewController.swift:237-255 | Wikipedia/Code/OnThisDayViewController.swift:241-260 \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. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NewsViewController.swift"},"region":{"startLine":237}}}],"partialFingerprints":{"codehealthFindingId/v1":"71b7b9467d746c327e94258d067c8c4ee7b085242a8d3ce3615fdf08323a5bd1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19 lines \u00D7 3): WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:56-74 | WMFComponents/Sources/WMFComponents/Components/Search/Results/WMFSearchResultsViewModel.swift:19-37 | WMFComponents/Sources/WMFComponents/Components/Settings/WMFSettingsViewModel.swift:108-126 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 3 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 3 times. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:56\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"e3953c558077bb64a09e623d5d96d006aa1a38563061907b6365ccaa390ae8f4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19 lines \u00D7 3): WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift:51-69 | WMFComponents/Sources/WMFComponents/Components/Settings/Push Notifications/WMFPushNotificationsSettingsView.swift:56-74 | WMFComponents/Sources/WMFComponents/Components/Settings/Storage and Syncing/WMFStorageAndSyncingSettingsView.swift:51-69 \u2014 before extracting anything, compare \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Push Notifications/WMFPushNotificationsSettingsView.swift\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 69 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. The two sit in different directories, so one cannot simply be deleted in favour of the other while both are reached separately: hoist the shared part into a location both already depend on and have each file call it, and retire whichever file turns out to have no caller of its own left. Extracting one helper per block leaves the fork in place. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift:51\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift"},"region":{"startLine":51}}}],"partialFingerprints":{"codehealthFindingId/v1":"3e25a477cb68dbd97a5df22517e9723a886395220d4673def1f7fe3f8ac597da"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19 lines \u00D7 3): WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift:683-701 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleSearchDataController.swift:29-47 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFRandomDataController.swift:45-63 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 3 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 3 times. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift:683\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleSearchDataController.swift:49\u0060 calls \u0060String\u0060 and \u0060WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift:702\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift"},"region":{"startLine":683}}}],"partialFingerprints":{"codehealthFindingId/v1":"f8a9f847db0fcd6d315c96f3f3c9b01433254564fb623ea16d9f1cf8e785ce60"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201319 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Games/Splash Screen/WMFGamesSplashScreenViewController.swift:40-58 | Wikipedia/Code/WMFWhichCameFirstArchiveViewController.swift:37-50 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Games/Splash Screen/WMFGamesSplashScreenViewController.swift:40\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Games/Splash Screen/WMFGamesSplashScreenViewController.swift"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"6d778bd0c6e858e28d8273285806efdc401c3a69f98e7c98c25550b69e208375"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18\u201319 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Suggested Edits/Image Recommendations/WMFImageRecommendationsViewController.swift:305-323 | WMFComponents/Sources/WMFComponents/Components/Suggested Edits/Image Recommendations/WMFImageRecommendationsViewController.swift:337-354 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Suggested Edits/Image Recommendations/WMFImageRecommendationsViewController.swift:305\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Suggested Edits/Image Recommendations/WMFImageRecommendationsViewController.swift"},"region":{"startLine":305}}}],"partialFingerprints":{"codehealthFindingId/v1":"35509738fd650e4e9a6c6431d385f459139f9e6fd09818e07892c50755bc1c07"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19 lines \u00D7 2): WMFData/Sources/WMFData/Service/WMFBasicService.swift:226-244 | WMFData/Sources/WMFData/Service/WMFBasicService.swift:250-268 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Service/WMFBasicService.swift:226\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Service/WMFBasicService.swift"},"region":{"startLine":226}}}],"partialFingerprints":{"codehealthFindingId/v1":"f4ad355935c2f48233f26a5ed22e31f5e0e15f508ac95c3bed666a0dab79c16c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18\u201319 lines \u00D7 2): WMF Framework/Fetcher.swift:298-316 | WMF Framework/Fetcher.swift:340-357 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/Fetcher.swift:298\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Fetcher.swift"},"region":{"startLine":298}}}],"partialFingerprints":{"codehealthFindingId/v1":"715ad9fb9c2b39be2cce60e5cb549cd4e72862a8893afd6f8aebcdbc463dc95a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19 lines \u00D7 2): WMF Framework/MediaWikiFetcher.swift:134-152 | WMF Framework/MediaWikiFetcher.swift:156-174 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/MediaWikiFetcher.swift:134\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/MediaWikiFetcher.swift"},"region":{"startLine":134}}}],"partialFingerprints":{"codehealthFindingId/v1":"81abb74f347884eb375fabbb65b94ac83350c5443b5036a499e8cf0c823418ff"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19 lines \u00D7 2): Wikipedia/Code/ColumnarCollectionViewController.swift:193-211 | Wikipedia/Code/InsertMediaSearchResultsCollectionViewController.swift:158-176 \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":"Wikipedia/Code/ColumnarCollectionViewController.swift"},"region":{"startLine":193}}}],"partialFingerprints":{"codehealthFindingId/v1":"189d9b9487a4c80cfade98a6c42de42d87e9b22f3c47e9e41e3b19ec5caa76fa"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19 lines \u00D7 2): WMF Framework/Remote Notifications/Model/RemoteNotificationFilterType.swift:193-211 | WMF Framework/Remote Notifications/Model/RemoteNotificationType.swift:39-57 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/Remote Notifications/Model/RemoteNotificationFilterType.swift:193\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Remote Notifications/Model/RemoteNotificationFilterType.swift"},"region":{"startLine":193}}}],"partialFingerprints":{"codehealthFindingId/v1":"69e209c1385c046baffff867f703681c2f6740db4b3b792256418827a8904b05"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16\u201318 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstViewController.swift:68-83 | WMFComponents/Sources/WMFComponents/Components/Year in Review/WMFYearInReviewHostingController.swift:177-194 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstViewController.swift:68\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstViewController.swift"},"region":{"startLine":68}}}],"partialFingerprints":{"codehealthFindingId/v1":"da0d939c9e46374ce98e1f95b606888a25c12ac4869e9dbc7deef053a52b157e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18 lines \u00D7 2): Wikipedia/Code/ArticleCollectionViewController.swift:197-214 | Wikipedia/Code/ExploreCardViewController.swift:597-614 \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":"Wikipedia/Code/ArticleCollectionViewController.swift"},"region":{"startLine":197}}}],"partialFingerprints":{"codehealthFindingId/v1":"6250cd917b34f29f50a3b3d138d31d05b1dda57632226d38ec8b092088453bc1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (17 lines \u00D7 3): WMF Framework/Widget/WidgetController.swift:372-388 | WMF Framework/Widget/WidgetController.swift:491-507 | WMF Framework/Widget/WidgetController.swift:555-571 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/Widget/WidgetController.swift:372\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060result\u0060 to \u0060WidgetContentFetcher.TopReadResult\u0060 in one and \u0060WidgetContentFetcher.FeaturedArticleResult\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Widget/WidgetController.swift"},"region":{"startLine":372}}}],"partialFingerprints":{"codehealthFindingId/v1":"e9d4edb901f79bc95e09448264d92fa6157fec7677f8702d4494a98f3bd09f47"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (17 lines \u00D7 2): WMF Framework/PermanentlyPersistableURLCache.swift:742-758 | WMF Framework/PermanentlyPersistableURLCache.swift:763-779 \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. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/PermanentlyPersistableURLCache.swift"},"region":{"startLine":742}}}],"partialFingerprints":{"codehealthFindingId/v1":"7bda2852bfdb464251d73e6120f46dc05afacc1cef70c23db9c926abc4e3b444"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (17 lines \u00D7 2): Wikipedia/Code/DiffTransformer.swift:209-225 | Wikipedia/Code/DiffTransformer.swift:232-248 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffTransformer.swift:209\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffTransformer.swift"},"region":{"startLine":209}}}],"partialFingerprints":{"codehealthFindingId/v1":"2be7588fcdea04c860939a56b8b92ec7f7aa27b9c9913ad34f5e0784629c13bf"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16\u201317 lines \u00D7 3): Wikipedia/Code/EvergreenAccountCreationCoordinator.swift:215-231 | Wikipedia/Code/EvergreenAccountCreationCoordinator.swift:233-249 | Wikipedia/Code/EvergreenAccountCreationCoordinator.swift:250-265 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/EvergreenAccountCreationCoordinator.swift:215\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060Wikipedia/Code/EvergreenAccountCreationCoordinator.swift:212\u0060 calls \u0060slides\u0060 and \u0060Wikipedia/Code/EvergreenAccountCreationCoordinator.swift:229\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/EvergreenAccountCreationCoordinator.swift"},"region":{"startLine":215}}}],"partialFingerprints":{"codehealthFindingId/v1":"79a9f0386c89948eb1d92929a8499c84fd895f36d33b6c221e4248c29ef3ee2f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15\u201316 lines \u00D7 3): WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/WMFHomeFeedWhatsDrivingSettingsView.swift:26-41 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/Main/WMFHomeFeedSettingsView.swift:21-35 | WMFComponents/Sources/WMFComponents/Components/Settings/WMFSettingsView.swift:95-110 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 3 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 3 times. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/WMFHomeFeedWhatsDrivingSettingsView.swift:26\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060WMFComponents/Sources/WMFComponents/Components/Settings/WMFSettingsView.swift:111\u0060 calls \u0060ignoresSafeArea\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/WMFHomeFeedWhatsDrivingSettingsView.swift:42\u0060 does not \u2014 after which the two agree again for 4 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/WMFHomeFeedWhatsDrivingSettingsView.swift"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"6a215ebaac27708ed0cbd5b869b2a2dbfbd1e93231403a04676088c3222816a7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201316 lines \u00D7 3): Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift:134-147 | Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift:192-207 | Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift:242-255 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift:134\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift"},"region":{"startLine":134}}}],"partialFingerprints":{"codehealthFindingId/v1":"d83f4e83b924a7f8b67aa2242bb6ab8766abe6d918a535e82fd7d95d126770cc"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7\u201316 lines \u00D7 2): Wikipedia/Code/SettingsTabViewController.swift:188-203 | Wikipedia/Code/WMFSettingsViewController\u002BExtensions.swift:14-20 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/SettingsTabViewController.swift:188\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/SettingsTabViewController.swift"},"region":{"startLine":188}}}],"partialFingerprints":{"codehealthFindingId/v1":"7498d93a2b2a5d9579e459cd43a704ae9863a5adc14f857079a693a54dcc3239"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16 lines \u00D7 2): WMF Framework/CacheDBWriting.swift:80-95 | WMF Framework/CacheDBWriting.swift:100-115 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/CacheDBWriting.swift:80\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/CacheDBWriting.swift"},"region":{"startLine":80}}}],"partialFingerprints":{"codehealthFindingId/v1":"e5ac3b32d80d0fd3ef308112855a68aa48ef4b286432d794808b895c9e017856"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16 lines \u00D7 2): Wikipedia/Code/DiffContainerViewController.swift:762-777 | Wikipedia/Code/DiffContainerViewController.swift:806-821 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffContainerViewController.swift:762\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":762}}}],"partialFingerprints":{"codehealthFindingId/v1":"c89368aeb2f3e77682fbf5edc3b80b82037e93ee60910f8f1700b4fa3875fda5"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift:130-144 | WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift:185-199 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift:130\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift:128\u0060 calls \u0060padding\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift:183\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"2587ea37698d8bf509a0e6a61aa027bbf518c850d06d54bdfc33fb1a81a217b4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201315 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift:93-107 | WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift:235-248 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift:93\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift"},"region":{"startLine":93}}}],"partialFingerprints":{"codehealthFindingId/v1":"a882399b569a1703e3f889c46f724deb629ef81ae232ff846587c3ddeb4135d7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201315 lines \u00D7 2): WMFData/Sources/WMFData/Data Controllers/Donor Experience/WMFFundraisingCampaignDataController.swift:185-199 | WMFData/Sources/WMFData/Data Controllers/Temp Accounts/WMFTempAccountDataController.swift:79-92 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Donor Experience/WMFFundraisingCampaignDataController.swift:185\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060(@Sendable (Result\u003CVoid, Error\u003E) -\u003E Void)? = nil\u0060 in one and \u0060(@Sendable (Result\u003CBool, Error\u003E) -\u003E Void)? = nil\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Donor Experience/WMFFundraisingCampaignDataController.swift"},"region":{"startLine":185}}}],"partialFingerprints":{"codehealthFindingId/v1":"c6b025423cf9166689951fcd91037b72bc86aeaaa58e27631171381940ddd3fb"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): WMF Framework/PageNamespace.swift:59-73 | Wikipedia/Code/NotificationsCenterAction.swift:72-86 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/PageNamespace.swift:59\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/PageNamespace.swift"},"region":{"startLine":59}}}],"partialFingerprints":{"codehealthFindingId/v1":"38145ec83c76c63b373ea8dd9c33650baa7ae1c80317a62b42cc9a99a6eaf491"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201315 lines \u00D7 2): WMF Framework/ThemeableTextField.swift:75-89 | Wikipedia/Code/ThemeableTextView.swift:203-216 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/ThemeableTextField.swift:75\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/ThemeableTextField.swift"},"region":{"startLine":75}}}],"partialFingerprints":{"codehealthFindingId/v1":"3700ef5479c99c1044b164463d888b063709be73d4b3dc1982aeccfa8942bc3c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): Wikipedia/Code/NewsViewController.swift:257-271 | Wikipedia/Code/OnThisDayViewController.swift:262-276 \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":"Wikipedia/Code/NewsViewController.swift"},"region":{"startLine":257}}}],"partialFingerprints":{"codehealthFindingId/v1":"e494111844111f69615842c000587d443b165585577f3c7d282f0848b884bda2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201315 lines \u00D7 2): Wikipedia/Code/ArticleViewController\u002BEditing.swift:409-423 | Wikipedia/Code/TalkPageViewController.swift:766-779 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ArticleViewController\u002BEditing.swift:409\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleViewController\u002BEditing.swift"},"region":{"startLine":409}}}],"partialFingerprints":{"codehealthFindingId/v1":"64659a41cd6c2686238571289963b04c201e6791c99fd141a58ddc7a066f42da"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): WMF Framework/WMFBlocksKit.swift:33-47 | WMF Framework/WMFBlocksKit.swift:85-99 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/WMFBlocksKit.swift:33\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/WMFBlocksKit.swift"},"region":{"startLine":33}}}],"partialFingerprints":{"codehealthFindingId/v1":"c0f8a044ac726e4478af5440c0d5153cf9410de85e1a05b6ef91c6ad2f802754"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 3): WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:63-76 | WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstViewModel.swift:49-62 | WMFComponents/Sources/WMFComponents/Components/Settings/WMFSettingsViewModel.swift:115-128 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 3 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 3 times. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:63\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstViewModel.swift:48\u0060 calls \u0060Sendable\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:62\u0060 does not \u2014 after which the two agree again for 4 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift"},"region":{"startLine":63}}}],"partialFingerprints":{"codehealthFindingId/v1":"0221d16df86868de2bfadc0a03bbfd7b2e266a6a1ef01ecd26971ee03a46cede"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Games/Splash Screen/WMFGamesSplashScreenViewController.swift:79-92 | WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstViewController.swift:29-42 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Games/Splash Screen/WMFGamesSplashScreenViewController.swift"},"region":{"startLine":79}}}],"partialFingerprints":{"codehealthFindingId/v1":"96aedb4302a6cca7c09b97a03fe172eab233180acde1a2520ffa60beb28a6990"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): WMF Framework/WMFArticle\u002BMigration.swift:21-34 | WMF Framework/WMFArticle\u002BMigration.swift:37-50 \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. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/WMFArticle\u002BMigration.swift"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"6a6d0ee7f44c2f804bebf4c75ecfd6b59a5fd78a1efa94385793d74fb4251d0c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): Wikipedia/Code/ArticlePlaceView.swift:261-274 | Wikipedia/Code/ArticlePlaceView.swift:488-501 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ArticlePlaceView.swift:261\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticlePlaceView.swift"},"region":{"startLine":261}}}],"partialFingerprints":{"codehealthFindingId/v1":"4da5e599805abda03705366850f3343803184bc0f9b7782396ec5448492aa936"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): Wikipedia/Code/DescriptionWelcomePageViewController.swift:34-47 | Wikipedia/Code/WMFWelcomePageViewController.swift:32-45 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DescriptionWelcomePageViewController.swift\u0060 and \u0060Wikipedia/Code/WMFWelcomePageViewController.swift\u0060 as WHOLE FILES: this scan already matched 9 separate duplicated blocks between them, totalling at least 84 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":"Wikipedia/Code/DescriptionWelcomePageViewController.swift"},"region":{"startLine":34}}}],"partialFingerprints":{"codehealthFindingId/v1":"f40b4891d17496a14e82d662f071bc49d55dc496630c2194980fbe05a41c1d13"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13\u201314 lines \u00D7 2): Wikipedia/Code/DiffController.swift:149-162 | Wikipedia/Code/DiffController.swift:164-176 \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":"Wikipedia/Code/DiffController.swift"},"region":{"startLine":149}}}],"partialFingerprints":{"codehealthFindingId/v1":"6b461e1a2a673b2204ff115a5506b4d7d3bb73a262440a271cb1242c6f57af51"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12\u201314 lines \u00D7 2): Wikipedia/Code/HelpViewController.swift:88-99 | Wikipedia/Code/ReferenceBackLinksViewController.swift:47-60 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ReferenceBackLinksViewController.swift:47\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/HelpViewController.swift"},"region":{"startLine":88}}}],"partialFingerprints":{"codehealthFindingId/v1":"e37a752f271ff3124a3ac7c15679f027979b7fcbb1a844accd52bf42b3753a6e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): Wikipedia/Code/ScrollViewGradientView.swift:39-52 | Wikipedia/Code/WMFImageGalleryGradientViews.swift:35-48 \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":"Wikipedia/Code/ScrollViewGradientView.swift"},"region":{"startLine":39}}}],"partialFingerprints":{"codehealthFindingId/v1":"6f66237e73b862f4e87550b51cb98e5a6c8582ec8a718e864956ffbbd814113e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): Wikipedia/Code/WMFAccountCreationViewController.swift:157-170 | Wikipedia/Code/WMFLoginViewController.swift:445-458 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAccountCreationViewController.swift:157\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAccountCreationViewController.swift"},"region":{"startLine":157}}}],"partialFingerprints":{"codehealthFindingId/v1":"f85452046db2cd2223c66744b5fd815e394c2f02757a17fd35abb4dfb44aa398"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): WMF Framework/MWKDataStore\u002BLegacyPageViews.swift:26-39 | WMF Framework/MWKDataStore\u002BLegacyPageViews.swift:72-85 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/MWKDataStore\u002BLegacyPageViews.swift:26\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/MWKDataStore\u002BLegacyPageViews.swift"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"69d569ad21c2e8ea95a744607f8d40103cdd8c981615a1193725bba15352b7ec"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift:90-103 | Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift:216-229 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift:90\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift:105\u0060 calls \u0060titleAction\u0060 and \u0060Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift:231\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NotificationsCenterCellViewModel\u002BSheetActionExtensions.swift"},"region":{"startLine":90}}}],"partialFingerprints":{"codehealthFindingId/v1":"43383d25348389135d8ede4782596e7aebbe54e9aa85ab4dc2abb21b3e23c831"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 6): WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift:31-43 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/WMFHomeFeedForYouSettingsView.swift:22-34 | WMFComponents/Sources/WMFComponents/Components/Settings/Push Notifications/WMFPushNotificationsSettingsView.swift:31-43 | WMFComponents/Sources/WMFComponents/Components/Settings/Search/WMFSearchSettingsView.swift:31-43 | WMFComponents/Sources/WMFComponents/Components/Settings/Storage and Syncing/WMFStorageAndSyncingSettingsView.swift:31-43 | WMFComponents/Sources/WMFComponents/Components/Settings/Year In Review/WMFYearInReviewSettingsView.swift:31-43 \u2014 before extracting anything, compare \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Push Notifications/WMFPushNotificationsSettingsView.swift\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 69 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. The two sit in different directories, so one cannot simply be deleted in favour of the other while both are reached separately: hoist the shared part into a location both already depend on and have each file call it, and retire whichever file turns out to have no caller of its own left. Extracting one helper per block leaves the fork in place. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift:31\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift:44\u0060 calls \u0060navigationTitle\u0060, \u0060navigationBarTitleDisplayMode\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/WMFHomeFeedForYouSettingsView.swift:35\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift"},"region":{"startLine":31}}}],"partialFingerprints":{"codehealthFindingId/v1":"b4c815cbc22dc1c117809fcd180b7055e2490109085eb7284ae72f4fad2a1617"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12\u201313 lines \u00D7 6): Wikipedia/Code/ActivityTabFunnel.swift:63-74 | Wikipedia/Code/ArticleTabsFunnel.swift:66-77 | Wikipedia/Code/DonateFunnel.swift:117-129 | Wikipedia/Code/EditInteractionFunnel.swift:80-92 | Wikipedia/Code/ImageRecommendationsFunnel.swift:85-97 | Wikipedia/Code/SearchFunnel.swift:47-59 \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 all 6 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ActivityTabFunnel.swift"},"region":{"startLine":63}}}],"partialFingerprints":{"codehealthFindingId/v1":"8bc373baf2beacaffe61208411001f7813719aa2674ace5b3bce6963f707dead"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11\u201313 lines \u00D7 4): Wikipedia/Code/ActivityTabViewController.swift:550-562 | Wikipedia/Code/DonationReminderSetupCoordinator.swift:150-160 | Wikipedia/Code/ExploreViewController.swift:1720-1730 | Wikipedia/Code/YearInReviewCoordinator.swift:109-120 \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 all 4 call sites, so a change lands once. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":550}}}],"partialFingerprints":{"codehealthFindingId/v1":"cb7ff2ae65f0c9c3880f6537e04f4d680af69f89ceb009576a1ddb805bb1cd6d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 3): WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift:149-161 | WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift:280-292 | WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift:369-381 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift:149\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift"},"region":{"startLine":149}}}],"partialFingerprints":{"codehealthFindingId/v1":"69fc9e5ae6588a5fc8b868b2cfad879be8f3aa5f4e80459d4da1e7cb4a43fb77"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 4): Wikipedia/Code/WMFAppViewController.swift:1145-1157 | Wikipedia/Code/WMFAppViewController.swift:1159-1171 | Wikipedia/Code/WMFAppViewController.swift:1173-1185 | Wikipedia/Code/WMFAppViewController.swift:1186-1198 \u2014 all 4 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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAppViewController.swift:1145\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060Wikipedia/Code/WMFAppViewController.swift:1145\u0060 calls \u0060WMFLocalizedString\u0060 and \u0060Wikipedia/Code/WMFAppViewController.swift:1186\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":1145}}}],"partialFingerprints":{"codehealthFindingId/v1":"c94df4466a3b96e5ba397f182b5859a161a49ca6cccce39eae5ede3ca6695f7b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 3): Wikipedia/Code/WMFAuthAccountCreationInfoFetcher.swift:23-35 | Wikipedia/Code/WMFAuthLoginInfoFetcher.swift:23-35 | Wikipedia/Code/WMFCurrentUserFetcher.swift:59-71 \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 all 3 call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAuthAccountCreationInfoFetcher.swift:23\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAuthAccountCreationInfoFetcher.swift"},"region":{"startLine":23}}}],"partialFingerprints":{"codehealthFindingId/v1":"8f5fc2e42e115675410dd2ff9d8925174bca69dcd45f3efca6e69b3c1e79fda4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Settings/Search/WMFSearchSettingsView.swift:51-63 | WMFComponents/Sources/WMFComponents/Components/Settings/Year In Review/WMFYearInReviewSettingsView.swift:51-63 \u2014 before extracting anything, compare \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Search/WMFSearchSettingsView.swift\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Year In Review/WMFYearInReviewSettingsView.swift\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 63 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. The two sit in different directories, so one cannot simply be deleted in favour of the other while both are reached separately: hoist the shared part into a location both already depend on and have each file call it, and retire whichever file turns out to have no caller of its own left. Extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Search/WMFSearchSettingsView.swift"},"region":{"startLine":51}}}],"partialFingerprints":{"codehealthFindingId/v1":"24415532f83c457ec897cd30b1761e74f93cc9d3b9029fbc4e25ba0dcd2501c2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9\u201313 lines \u00D7 2): WMF Framework/CacheController.swift:79-91 | WMF Framework/Event Platform/StorageManager.swift:33-41 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/CacheController.swift:79\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/CacheController.swift"},"region":{"startLine":79}}}],"partialFingerprints":{"codehealthFindingId/v1":"8dbdee218b2af1557b8d42efb4acdd3cb34c2ee36328f0584c6df76a3af8dde4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12\u201313 lines \u00D7 2): WMF Framework/ReadingListsAPIController.swift:285-296 | WMF Framework/ReadingListsAPIController.swift:393-405 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/ReadingListsAPIController.swift:285\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping (_ listIDs: []?,_ error: Error?) -\u003E Swift.Void\u0060 in one and \u0060@escaping (_ entryIDs: []?,_ error: Error?) -\u003E Swift.Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/ReadingListsAPIController.swift"},"region":{"startLine":285}}}],"partialFingerprints":{"codehealthFindingId/v1":"d24d2c1662d933bed7b8394a545b8492a6bd3ac55d6ff3f2519b3af11f679fd3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): Wikipedia/Code/ReadingListEntryCollectionViewController.swift:169-181 | Wikipedia/Code/SavedAllArticlesCoordinator.swift:272-284 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ReadingListEntryCollectionViewController.swift:169\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ReadingListEntryCollectionViewController.swift"},"region":{"startLine":169}}}],"partialFingerprints":{"codehealthFindingId/v1":"029779824d452991e9908b817d9d371f05166b3424b9aad0cd840cdd3fd84101"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): Wikipedia/Code/TalkPageCellCommentView.swift:130-142 | Wikipedia/Code/TalkPageCellTopicView.swift:380-392 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/TalkPageCellCommentView.swift:130\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageCellCommentView.swift"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"076f493a108f370bc42e3f0c2c6561b4448b744bd3ee702d25dab6bf08c6c9c4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 19): WMF Framework/ArticleSummary.swift:79-90 | WMF Framework/NavigationState.swift:89-100 | WMF Framework/RelatedResponse.swift:88-99 | WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabViewModel.swift:143-154 | WMFComponents/Sources/WMFComponents/Components/Article Tabs/WMFArticleTabsViewModel.swift:135-146 | WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:77-88 | WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorLocalizedStrings.swift:120-131 | WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorTextFrameworkMediator.swift:45-56 | WMFComponents/Sources/WMFComponents/Components/Profile/WMFProfileViewModel.swift:57-68 | WMFComponents/Sources/WMFComponents/Components/Saved/All Articles/WMFSavedAllArticlesViewModel.swift:36-47 | WMFComponents/Sources/WMFComponents/Components/Settings/WMFSettingsViewModel.swift:131-142 | WMFComponents/Sources/WMFComponents/Components/Shared/Page/WMFPageRow.swift:39-50 | WMFComponents/Sources/WMFComponents/Components/Suggested Edits/Image Recommendations/WMFImageRecommendationsViewModel.swift:81-92 | WMFComponents/Sources/WMFComponents/Components/Suggested Edits/Image Recommendations/WMFImageRecommendationsViewModel.swift:112-123 | WMFComponents/Sources/WMFComponents/Components/Watchlist/Filter/WMFWatchlistFilterViewModel.swift:55-66 | WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewModel.swift:29-40 | WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewModel.swift:68-79 | WMFComponents/Sources/WMFComponents/Utility/HTMLUtils.swift:38-49 | WMFData/Sources/WMFData/Data Controllers/Activity Tab/WMFActivityTabDataController.swift:518-529 \u2014 there are 19 copies across 17 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 19 sites; resolving a subset leaves the remainder to drift apart. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/ArticleSummary.swift:79\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060articleDescription\u0060 to \u0060String? = nil\u0060 in one and \u0060String?\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/ArticleSummary.swift"},"region":{"startLine":79}}}],"partialFingerprints":{"codehealthFindingId/v1":"53a60146ac85fb7a4cae94464652ea45fea2d992406fd74d6b6155bb790c330d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 8): WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift:16-27 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsView.swift:14-25 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/WMFHomeFeedForYouSettingsView.swift:14-25 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/WMFHomeFeedWhatsDrivingSettingsView.swift:14-25 | WMFComponents/Sources/WMFComponents/Components/Settings/Push Notifications/WMFPushNotificationsSettingsView.swift:16-27 | WMFComponents/Sources/WMFComponents/Components/Settings/Search/WMFSearchSettingsView.swift:16-27 | WMFComponents/Sources/WMFComponents/Components/Settings/Storage and Syncing/WMFStorageAndSyncingSettingsView.swift:16-27 | WMFComponents/Sources/WMFComponents/Components/Settings/Year In Review/WMFYearInReviewSettingsView.swift:16-27 \u2014 before extracting anything, compare \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Push Notifications/WMFPushNotificationsSettingsView.swift\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 69 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. The two sit in different directories, so one cannot simply be deleted in favour of the other while both are reached separately: hoist the shared part into a location both already depend on and have each file call it, and retire whichever file turns out to have no caller of its own left. Extracting one helper per block leaves the fork in place. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift:16\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060viewModel\u0060 to \u0060WMFAccountSettingsViewModel\u0060 in one and \u0060WMFHomeFeedCommunitySettingsViewModel\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsView.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"60451dfc957e65e653351683baec255a1fc7d317e92a94dad4d42f8b1bfb417e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 7): WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:65-76 | WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:243-254 | WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstViewModel.swift:51-62 | WMFComponents/Sources/WMFComponents/Components/Reading Challenge Widget/WMFRandomWidgetViewModel.swift:54-65 | WMFComponents/Sources/WMFComponents/Components/Settings/WMFSettingsViewModel.swift:117-128 | WMFComponents/Sources/WMFComponents/Utility/HTMLUtils.swift:36-47 | Wikipedia/Code/ArticleCoordinator.swift:179-190 \u2014 there are 7 copies across 6 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 7 sites; resolving a subset leaves the remainder to drift apart. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:65\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstViewModel.swift:48\u0060 calls \u0060Sendable\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:62\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift"},"region":{"startLine":65}}}],"partialFingerprints":{"codehealthFindingId/v1":"3926c87b80762c215fb3840ac1e02fe50250e62238ad2e0756b5643b9bdfa3e0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9\u201312 lines \u00D7 4): Wikipedia/Code/DescriptionEditViewController.swift:147-155 | Wikipedia/Code/DescriptionEditViewController.swift:170-178 | Wikipedia/Code/EditSaveViewController.swift:262-273 | Wikipedia/Code/EditSaveViewController.swift:296-307 \u2014 there are 4 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 4 sites; resolving a subset leaves the remainder to drift apart. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DescriptionEditViewController.swift:147\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DescriptionEditViewController.swift"},"region":{"startLine":147}}}],"partialFingerprints":{"codehealthFindingId/v1":"ba035ce87a9b0cbbc093c8e612e5c40f686ab90e4f81c97b9c82fe2ce49c6a3e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 3): Wikipedia/Code/ArticleViewController\u002BEditing.swift:400-411 | Wikipedia/Code/DescriptionEditViewController.swift:400-411 | Wikipedia/Code/TalkPageViewController.swift:757-768 \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 all 3 call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ArticleViewController\u002BEditing.swift:400\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleViewController\u002BEditing.swift"},"region":{"startLine":400}}}],"partialFingerprints":{"codehealthFindingId/v1":"54adb3da958b40eeae94202872d39411928d8f13dc2bb900ad39c0cb9d81f9fe"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/Base/WMFEditorToolbarButton.swift:36-47 | WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/WMFEditorToolbarNavigatorButton.swift:32-43 \u2014 before extracting anything, compare \u0060WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/Base/WMFEditorToolbarButton.swift\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/WMFEditorToolbarNavigatorButton.swift\u0060 as WHOLE FILES: 85% of the shorter file\u0027s lines also appear in the other, so this reads as one file having been copied from the other rather than as a helper waiting to be extracted. The 2 duplicated block(s) this scan matched between them are fragments of that copy, not the extent of it \u2014 treat the file pair as the unit. The two sit in different directories, so one cannot simply be deleted in favour of the other while both are reached separately: hoist the shared part into a location both already depend on and have each file call it, and retire whichever file turns out to have no caller of its own left. Extracting one helper per block leaves the fork in place. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/Base/WMFEditorToolbarButton.swift:36\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/Base/WMFEditorToolbarButton.swift"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"0e4d2ad80d09c58413da9f4b1de0463fc11c05ebc4a059d3a7b6e4b99aea9a92"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Shared/Page/WMFPageRow.swift:66-77 | WMFComponents/Sources/WMFComponents/Components/Shared/Page/WMFPageRow.swift:136-147 \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":"WMFComponents/Sources/WMFComponents/Components/Shared/Page/WMFPageRow.swift"},"region":{"startLine":66}}}],"partialFingerprints":{"codehealthFindingId/v1":"f8fddfa2457d6f1ec69a184baf3ef56d77d650b8ecb7cd6352641e0501f22c03"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11\u201312 lines \u00D7 2): WMF Framework/CacheController.swift:242-253 | WMF Framework/CacheController.swift:358-368 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/CacheController.swift:242\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/CacheController.swift"},"region":{"startLine":242}}}],"partialFingerprints":{"codehealthFindingId/v1":"329fd45ac9f608d7374e5cee225d781bad4dd5ed328856eb8ac9c1a6a46d98be"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11\u201312 lines \u00D7 2): Wikipedia/Code/AppOnboardingCoordinator.swift:35-46 | Wikipedia/Code/AppOnboardingCoordinator.swift:174-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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/AppOnboardingCoordinator.swift:35\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/AppOnboardingCoordinator.swift"},"region":{"startLine":35}}}],"partialFingerprints":{"codehealthFindingId/v1":"aa9f7efb932b99a58db1aaa47a7af999557499984ccb49ca1bb8aa0f6a18f8fc"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): Wikipedia/Code/DescriptionWelcomePageViewController.swift:193-204 | Wikipedia/Code/WMFWelcomePageViewController.swift:270-281 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DescriptionWelcomePageViewController.swift\u0060 and \u0060Wikipedia/Code/WMFWelcomePageViewController.swift\u0060 as WHOLE FILES: this scan already matched 9 separate duplicated blocks between them, totalling at least 84 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":"Wikipedia/Code/DescriptionWelcomePageViewController.swift"},"region":{"startLine":193}}}],"partialFingerprints":{"codehealthFindingId/v1":"fb445cf9f3553db812df1138c371a4c0c1a341b56016437ea97cc83feab487b3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): Wikipedia/Code/DiffFetcher.swift:198-209 | Wikipedia/Code/DiffFetcher.swift:242-253 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffFetcher.swift:198\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping (Result\u003CWMFPageHistoryRevision, Error\u003E) -\u003E Void\u0060 in one and \u0060@escaping (Result\u003CString, Error\u003E) -\u003E Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffFetcher.swift"},"region":{"startLine":198}}}],"partialFingerprints":{"codehealthFindingId/v1":"328e015e2bd1fe54b73e115c8f2be7fd17be942c0819f456e7be76b62bbc982e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): Wikipedia/Code/ExploreViewController.swift:138-149 | Wikipedia/Code/SavedViewController.swift:266-277 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ExploreViewController.swift:138\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":138}}}],"partialFingerprints":{"codehealthFindingId/v1":"f733c8f2fcdd72c8734c571a92cfc85b39338c33f6261534a2f3e21eecdf3278"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): Wikipedia/Code/SizeThatFitsReusableView.swift:67-78 | Wikipedia/Code/SizeThatFitsView.swift:35-46 \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":"Wikipedia/Code/SizeThatFitsReusableView.swift"},"region":{"startLine":67}}}],"partialFingerprints":{"codehealthFindingId/v1":"0f83213b3d8cad374d1f9d41eab4bc0926471f9bc7981034f8259627f0f4e1ab"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10\u201312 lines \u00D7 2): Wikipedia/Code/ViewControllerRouter.swift:235-246 | Wikipedia/Code/WMFAppViewController\u002BExtensions.swift:456-465 \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":"Wikipedia/Code/ViewControllerRouter.swift"},"region":{"startLine":235}}}],"partialFingerprints":{"codehealthFindingId/v1":"c1e58f5289bca14d62be2d73f1d32ca20cbf0834b875787759190093f1292c36"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): Wikipedia/Code/WMFAccountCreationViewController.swift:134-145 | Wikipedia/Code/WMFLoginViewController.swift:114-125 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAccountCreationViewController.swift:134\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAccountCreationViewController.swift"},"region":{"startLine":134}}}],"partialFingerprints":{"codehealthFindingId/v1":"e3883cf080529fdc44a426d3a4d087bf4226fe3a13226f7ebb8191116e120784"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): Wikipedia/Code/WatchlistController.swift:49-60 | Wikipedia/Code/WatchlistController.swift:229-240 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WatchlistController.swift:49\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WatchlistController.swift"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"be4d98ea38efb34da6b58e8f0fb62df35ebab888f50896ba567e861b88f69f42"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): WMFData/Sources/WMFData/Extensions/URL\u002BAPI.swift:81-92 | WMFData/Sources/WMFData/Extensions/URL\u002BAPI.swift:96-107 \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. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Extensions/URL\u002BAPI.swift"},"region":{"startLine":81}}}],"partialFingerprints":{"codehealthFindingId/v1":"8274a8bc0810e250ba933d5b22b94b70a8f2e4f993b41483bf2b84a132069f27"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 3): WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:243-254 | WMFComponents/Sources/WMFComponents/Components/Reading Challenge Widget/WMFRandomWidgetViewModel.swift:54-65 | WMFComponents/Sources/WMFComponents/Components/Search/Results/WMFSearchResultsViewModel.swift:141-151 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 3 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 3 times. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift:243\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewModel.swift"},"region":{"startLine":243}}}],"partialFingerprints":{"codehealthFindingId/v1":"f0eff0081eb562a48b24b5c3ac2894500748abc9193d93bdae71d38dd945aca4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 3): WMF Framework/CacheFileWriterHelper.swift:16-26 | WMF Framework/CacheFileWriterHelper.swift:32-42 | WMF Framework/CacheFileWriterHelper.swift:59-69 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/CacheFileWriterHelper.swift:16\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping (FileSaveResult) -\u003E Void\u0060 in one and \u0060(FileSaveResult) -\u003E Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/CacheFileWriterHelper.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"a5bca94ef86b152aa11ab91798beab3b2e3000d6cebb9b074e3851e887cec140"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 3): Wikipedia/Code/DonateCoordinator.swift:658-668 | Wikipedia/Code/DonateCoordinator.swift:672-682 | Wikipedia/Code/DonateCoordinator.swift:685-695 \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. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":658}}}],"partialFingerprints":{"codehealthFindingId/v1":"104cb02c658679612687e62fa23686429226cedbc5400b945a06acada894b643"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10\u201311 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabInfoCardView.swift:56-65 | WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabInfoCardView.swift:67-77 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabInfoCardView.swift:56\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabInfoCardView.swift"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"639e84b3d02700a7144c9bc6e31caf22e999824c00663870821010ec53db9271"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10\u201311 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFImpactViews.swift:147-156 | WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFImpactViews.swift:171-181 \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. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFImpactViews.swift:184\u0060 calls \u0060HStack\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFImpactViews.swift:157\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFImpactViews.swift"},"region":{"startLine":147}}}],"partialFingerprints":{"codehealthFindingId/v1":"fda00a1ba7ab113ef4dd942387373ec75c9abac2a3316a6e532d8905a2102c74"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift:64-74 | WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift:97-107 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift:64\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"2580d560b291bdfebc39395e828d64a98b4f33f3075132c9d5c4628ec5eae095"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:437-447 | WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:489-499 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:437\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift"},"region":{"startLine":437}}}],"partialFingerprints":{"codehealthFindingId/v1":"41be779391580906323058820d3a5d5f2e86a677466db6b8cc910b1f5dafc0d0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10\u201311 lines \u00D7 2): WMF Framework/Remote Notifications/RemoteNotificationsController.swift:429-438 | WMF Framework/Remote Notifications/RemoteNotificationsController.swift:440-450 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/Remote Notifications/RemoteNotificationsController.swift:440\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Remote Notifications/RemoteNotificationsController.swift"},"region":{"startLine":429}}}],"partialFingerprints":{"codehealthFindingId/v1":"823ffc44b692a7082a9996b7672ee94c216add84b31571d06dd69200402f4305"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): Widgets/Widgets/FeaturedArticleWidget.swift:298-308 | Widgets/Widgets/PictureOfTheDayWidget.swift:263-273 \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":"Widgets/Widgets/FeaturedArticleWidget.swift"},"region":{"startLine":298}}}],"partialFingerprints":{"codehealthFindingId/v1":"266b4e2376a52214240a5aef12fb4b3453a363c1edd8fbc822ad15b6b6fe03eb"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): Wikipedia/Code/DonateCoordinator.swift:894-904 | Wikipedia/Code/DonateCoordinator.swift:1019-1029 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DonateCoordinator.swift:894\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":894}}}],"partialFingerprints":{"codehealthFindingId/v1":"8000698ea92fb8be7f329f6234cf66696b944694f6de5d0d924f92562534cb61"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): Wikipedia/Code/SavedArticlesFetcher.swift:182-192 | Wikipedia/Code/SavedArticlesFetcher.swift:230-240 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/SavedArticlesFetcher.swift:182\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/SavedArticlesFetcher.swift"},"region":{"startLine":182}}}],"partialFingerprints":{"codehealthFindingId/v1":"5b2934cbe60ba2d383741a6e811aacce5edf6fe6f880e7d464ab85acfb0c19d7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): Wikipedia/Code/ShareActivityController.swift:178-188 | Wikipedia/Code/ShareActivityController.swift:196-206 \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":"Wikipedia/Code/ShareActivityController.swift"},"region":{"startLine":178}}}],"partialFingerprints":{"codehealthFindingId/v1":"6426b25dd85a8286fd6604e27e390d2d1335e69c1ff45f6f2f1b6478b6a10f7f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9\u201311 lines \u00D7 2): Wikipedia/Code/TalkPageFetcher.swift:199-209 | Wikipedia/Code/TalkPageFetcher.swift:222-230 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/TalkPageFetcher.swift:199\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageFetcher.swift"},"region":{"startLine":199}}}],"partialFingerprints":{"codehealthFindingId/v1":"512d2043c607369d66f704780609e825b12ed261fa26062b7d8aca780e8ed8c1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift:232-242 | Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift:259-269 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift:232\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift"},"region":{"startLine":232}}}],"partialFingerprints":{"codehealthFindingId/v1":"df9b039fd59ef1382d12411949e060c15527f259b7d0de4a8143c7ae4657eff4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (2\u201311 lines \u00D7 14): WMF Framework/Remote Notifications/RemoteNotificationsController.swift:565-567 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/Main/WMFHomeFeedSettingsViewModel.swift:13-14 | Wikipedia/Code/ArticleViewController\u002BDonationReminder.swift:204-205 | Wikipedia/Code/DiffListChangeItemViewModel.swift:267-268 | Wikipedia/Code/DonateCoordinator.swift:519-521 | Wikipedia/Code/DonateCoordinator.swift:533-535 | Wikipedia/Code/FindAndReplaceKeyboardBar.swift:345-346 | Wikipedia/Code/NotificationsCenterViewController.swift:561-562 | Wikipedia/Code/WMFAppViewController\u002BExtensions.swift:1067-1077 | Wikipedia/Code/WMFAppViewController\u002BExtensions.swift:1092-1093 | Wikipedia/Code/WMFAppViewController\u002BExtensions.swift:1102-1105 | Wikipedia/Code/WMFAppViewController\u002BExtensions.swift:1124-1126 | Wikipedia/Code/WMFAppViewController\u002BExtensions.swift:1134-1141 | Wikipedia/Code/WatchlistController.swift:131-132 \u2014 there are 14 copies across 9 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 14 sites; resolving a subset leaves the remainder to drift apart. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAppViewController\u002BExtensions.swift:1067\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Remote Notifications/RemoteNotificationsController.swift"},"region":{"startLine":565}}}],"partialFingerprints":{"codehealthFindingId/v1":"889a2738bbd66c523d2be6ca5fa890ddb6d13fab18729af71121b8fef9db632c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): WMF Framework/Remote Notifications/Model/RemoteNotificationFilterType.swift:109-119 | WMF Framework/Remote Notifications/Model/RemoteNotificationFilterType.swift:149-159 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/Remote Notifications/Model/RemoteNotificationFilterType.swift:109\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Remote Notifications/Model/RemoteNotificationFilterType.swift"},"region":{"startLine":109}}}],"partialFingerprints":{"codehealthFindingId/v1":"2e620ff5c4b036ea1800bd14a3ac6587dab49f46bb7e33390771ac456849604d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): Wikipedia/Code/ArticleViewController\u002BArticleToolbarHandling.swift:16-26 | Wikipedia/Code/ArticleViewController\u002BArticleToolbarHandling.swift:30-40 \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":"Wikipedia/Code/ArticleViewController\u002BArticleToolbarHandling.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"3281f39ecc4288d4474dff536c433df75c01bd2bea85da045b9845517f4a7040"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): Wikipedia/Code/TalkPageViewController\u002BFindInPage.swift:79-89 | Wikipedia/Code/TalkPageViewController\u002BFindInPage.swift:92-102 \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":"Wikipedia/Code/TalkPageViewController\u002BFindInPage.swift"},"region":{"startLine":79}}}],"partialFingerprints":{"codehealthFindingId/v1":"a7ab4082795bcb357a2715816dfa774f3ee161a2fc209844b8af6d1c7f00e472"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 4): WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:338-347 | WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:379-388 | WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:421-430 | WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:471-480 \u2014 all 4 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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:338\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping @Sendable (Result\u003CVoid, Error\u003E) -\u003E Void\u0060 in one and \u0060@escaping @Sendable (Result\u003CWMFUndoOrRollbackResult, Error\u003E) -\u003E Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:469\u0060 calls \u0060String\u0060 and \u0060WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift:378\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift"},"region":{"startLine":338}}}],"partialFingerprints":{"codehealthFindingId/v1":"e3308a49db81e8204785a7db877660e6adc771f613e02a00825c3ff88eee1d89"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 3): WMF Framework/Remote Notifications/RemoteNotificationsController.swift:128-137 | WMF Framework/Remote Notifications/RemoteNotificationsController.swift:178-187 | WMF Framework/Remote Notifications/RemoteNotificationsController.swift:196-205 \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. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Remote Notifications/RemoteNotificationsController.swift"},"region":{"startLine":128}}}],"partialFingerprints":{"codehealthFindingId/v1":"42b39216e21d621ce5de4260296bec247ea29f491decfc097455b03be750a717"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 3): Wikipedia/Code/ActivityTabViewController.swift:112-121 | Wikipedia/Code/PlacesViewController.swift:201-211 | Wikipedia/Code/SearchViewController.swift:368-377 \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 all 3 call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ActivityTabViewController.swift:112\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":112}}}],"partialFingerprints":{"codehealthFindingId/v1":"cddee1d2089dd6dbfafb23e30285d9c5f57142dc86a7a9dfca89e66a804b8f27"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7\u201310 lines \u00D7 3): Wikipedia/Code/ArticlePeekPreviewViewController.swift:158-167 | Wikipedia/Code/SavedAllArticlesCoordinator.swift:186-195 | Wikipedia/Code/WhichCameFirstCoordinator.swift:366-372 \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 all 3 call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ArticlePeekPreviewViewController.swift:158\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060Wikipedia/Code/ArticlePeekPreviewViewController.swift:157\u0060 calls \u0060WMFArticle\u0060 and \u0060Wikipedia/Code/WhichCameFirstCoordinator.swift:365\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticlePeekPreviewViewController.swift"},"region":{"startLine":158}}}],"partialFingerprints":{"codehealthFindingId/v1":"928a9f970da83cd62ebdaea4cea249688c5d5a3dec9aeb61fd1e464bc53c3256"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 3): Wikipedia/Code/DiffFetcher.swift:201-210 | Wikipedia/Code/DiffFetcher.swift:245-254 | Wikipedia/Code/GlobalUserInfoFetcher.swift:18-28 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DiffFetcher.swift\u0060 and \u0060Wikipedia/Code/GlobalUserInfoFetcher.swift\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 43 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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffFetcher.swift:201\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping (Result\u003CWMFPageHistoryRevision, Error\u003E) -\u003E Void\u0060 in one and \u0060@escaping (Result\u003CString, Error\u003E) -\u003E Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffFetcher.swift"},"region":{"startLine":201}}}],"partialFingerprints":{"codehealthFindingId/v1":"b93e9d3597ad83755ef56fd89a2070dd39a7a010d0d5edc0fdb0cceea8b0883b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 3): Wikipedia/Code/TalkPageFetcher.swift:128-137 | Wikipedia/Code/TalkPageFetcher.swift:164-173 | Wikipedia/Code/TalkPageFetcher.swift:233-242 \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. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping (Result\u003CBool, Error\u003E) -\u003E Void\u0060 in one and \u0060@escaping (Result\u003C[String], Error\u003E) -\u003E Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageFetcher.swift"},"region":{"startLine":128}}}],"partialFingerprints":{"codehealthFindingId/v1":"b1837ebe1fb59257465aad3d008c4fe8db93d2bf581ec168e7173d492e62bcd0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7\u201310 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Home/WMFForYouEndOfFeedCardView.swift:124-133 | WMFComponents/Sources/WMFComponents/Components/Home/WMFForYouView.swift:930-936 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Home/WMFForYouEndOfFeedCardView.swift:124\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Home/WMFForYouEndOfFeedCardView.swift"},"region":{"startLine":124}}}],"partialFingerprints":{"codehealthFindingId/v1":"cfe38e97ccb67764b549463c6b5d334c6689b943f450e732b73ccf10b9be4662"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/Your Interests/WMFHomeFeedInterestsSettingsView.swift:318-327 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/Your Interests/WMFHomeFeedInterestsSettingsView.swift:343-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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/Your Interests/WMFHomeFeedInterestsSettingsView.swift:318\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/Your Interests/WMFHomeFeedInterestsSettingsView.swift"},"region":{"startLine":318}}}],"partialFingerprints":{"codehealthFindingId/v1":"da83eceafe8568944eb96d137ac27deda2c1456e65ce92947d69b4146fd4a3a9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): WMF Framework/ArticleCacheDBWriter\u002BSyncResources.swift:215-224 | WMF Framework/ArticleCacheResourceDBWriting.swift:82-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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/ArticleCacheDBWriter\u002BSyncResources.swift:215\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/ArticleCacheDBWriter\u002BSyncResources.swift"},"region":{"startLine":215}}}],"partialFingerprints":{"codehealthFindingId/v1":"b3ecaadc67463aa8af78ac7cf897b25996a94e04d983bea2dd9d38ede54f29ec"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): WMF Framework/ImageCacheDBWriter.swift:44-53 | Wikipedia/Code/ArticleCacheDBWriter.swift:119-128 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/ImageCacheDBWriter.swift:44\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/ImageCacheDBWriter.swift"},"region":{"startLine":44}}}],"partialFingerprints":{"codehealthFindingId/v1":"b1963d64b7b6d53dfabb83bfbf33036db9fa7d95a1348da83f0275ad454ed5a3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): Widgets/Widgets/OnThisDayWidget.swift:47-56 | Widgets/Widgets/PictureOfTheDayWidget.swift:155-164 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Widgets/Widgets/OnThisDayWidget.swift:47\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping (Timeline\u003COnThisDayEntry\u003E) -\u003E Void\u0060 in one and \u0060@escaping (Timeline\u003CPictureOfTheDayEntry\u003E) -\u003E Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Widgets/Widgets/OnThisDayWidget.swift"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"5f2732d4aaacbf1ae35610234e8c06dd4bf8a2dfefb7861cab18c7ecff8ed3e2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9\u201310 lines \u00D7 2): Wikipedia/Code/ActivityTabViewController.swift:150-159 | Wikipedia/Code/HomeViewController.swift:337-345 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ActivityTabViewController.swift:150\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":150}}}],"partialFingerprints":{"codehealthFindingId/v1":"52c89cbccf506cf86d9cb23d8dd84392615e551f3e5a1352ab287dd131134f53"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): Wikipedia/Code/ArticleCollectionViewController.swift:138-147 | Wikipedia/Code/ReadingListEntryCollectionViewController.swift:459-468 \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":"Wikipedia/Code/ArticleCollectionViewController.swift"},"region":{"startLine":138}}}],"partialFingerprints":{"codehealthFindingId/v1":"02304fdf60b975be1f0cbdde38b259ee6cbcd98a0bd8672d64a0687df83ea9cc"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): Wikipedia/Code/HomeFeedSettingsCoordinator.swift:90-99 | Wikipedia/Code/HomeFeedSettingsCoordinator.swift:175-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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/HomeFeedSettingsCoordinator.swift:90\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/HomeFeedSettingsCoordinator.swift"},"region":{"startLine":90}}}],"partialFingerprints":{"codehealthFindingId/v1":"c76953b0af40e2f6eba148374ee9ff0f6589203c94e9480c3cb47b87d29f0654"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): Wikipedia/Code/ScrollableEducationPanelViewController.swift:339-348 | Wikipedia/Code/ScrollableEducationPanelViewController.swift:352-361 \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":"Wikipedia/Code/ScrollableEducationPanelViewController.swift"},"region":{"startLine":339}}}],"partialFingerprints":{"codehealthFindingId/v1":"bb47219f30e4ada0299b9d7a6ff7369010c340c98f4dd865a45d53393fcd17b6"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): Wikipedia/Code/UIViewController\u002BExtensions.swift:193-202 | Wikipedia/Code/UIViewController\u002BExtensions.swift:214-223 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/UIViewController\u002BExtensions.swift:193\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/UIViewController\u002BExtensions.swift"},"region":{"startLine":193}}}],"partialFingerprints":{"codehealthFindingId/v1":"6f6709ff589410b16e5d948929b83c688f3affb8050247f46e22ac0cb89d49b2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): Wikipedia/Code/ViewControllerRouter.swift:130-139 | Wikipedia/Code/ViewControllerRouter.swift:143-152 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ViewControllerRouter.swift:130\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ViewControllerRouter.swift"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"4594a227f81094138ca3af5b9fa6ce114ea8cabfe34c938137eed095f6cda71c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): Wikipedia/Code/WMFAuthenticationManager.swift:293-302 | Wikipedia/Code/WMFAuthenticationManager.swift:364-373 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAuthenticationManager.swift:293\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060Wikipedia/Code/WMFAuthenticationManager.swift:375\u0060 calls \u0060submitInteraction\u0060 and \u0060Wikipedia/Code/WMFAuthenticationManager.swift:303\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAuthenticationManager.swift"},"region":{"startLine":293}}}],"partialFingerprints":{"codehealthFindingId/v1":"9923d90c64c778960d7436787b456b18c99c18bb8d2e2c60259d516ac9495924"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 5): WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift:691-699 | WMFData/Sources/WMFData/Data Controllers/Shared/UserContributionsDataController.swift:23-31 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleSearchDataController.swift:37-45 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFRandomDataController.swift:53-61 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFRelatedPagesDataController.swift:56-64 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 5 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 5 times. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift:691\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060WMFData/Sources/WMFData/Data Controllers/Shared/UserContributionsDataController.swift:21\u0060 calls \u0060wikipedia\u0060 and \u0060WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift:689\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift"},"region":{"startLine":691}}}],"partialFingerprints":{"codehealthFindingId/v1":"556a7ec931edebd9486f1ebfb2a4e56a9e03be487e1c32dfcb577dfa0b50e829"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 4): Wikipedia/Code/WMFAuthAccountCreationInfoFetcher.swift:26-35 | Wikipedia/Code/WMFAuthLoginInfoFetcher.swift:26-35 | Wikipedia/Code/WMFCaptchaResetter.swift:23-31 | Wikipedia/Code/WMFCurrentUserFetcher.swift:62-71 \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 all 4 call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAuthAccountCreationInfoFetcher.swift:26\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAuthAccountCreationInfoFetcher.swift"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"6830e6ce1f84540103d2d06e35c1b9afd3e787232eca9142857819383d3d3bd8"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 3): WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleSearchDataController.swift:50-58 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFRandomDataController.swift:69-77 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFRelatedPagesDataController.swift:74-82 \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 all 3 call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleSearchDataController.swift:50\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleSearchDataController.swift:49\u0060 calls \u0060String\u0060 and \u0060WMFData/Sources/WMFData/Data Controllers/Shared/WMFRandomDataController.swift:68\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleSearchDataController.swift"},"region":{"startLine":50}}}],"partialFingerprints":{"codehealthFindingId/v1":"c1396353a941017e2807b2bdc47da864d5568185a4752909531d3d5ccbbe04c4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7\u20139 lines \u00D7 3): WMFData/Sources/WMFData/Data Controllers/Shared/WMFPageTopicsDataController.swift:34-42 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFPageTopicsDataController.swift:248-256 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFPageViewsDataController.swift:247-253 \u2014 there are 3 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 3 sites; resolving a subset leaves the remainder to drift apart. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Shared/WMFPageTopicsDataController.swift:34\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Shared/WMFPageTopicsDataController.swift"},"region":{"startLine":34}}}],"partialFingerprints":{"codehealthFindingId/v1":"b0584c0f7337cbe00f278d53ec26e19ae004e6c3ad4da63bdd27fd60e8236309"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8\u20139 lines \u00D7 3): Wikipedia/Code/AppOnboardingCoordinator.swift:186-193 | Wikipedia/Code/HomeFeedSettingsCoordinator.swift:98-105 | Wikipedia/Code/HomeFeedSettingsCoordinator.swift:183-191 \u2014 there are 3 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 3 sites; resolving a subset leaves the remainder to drift apart. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/AppOnboardingCoordinator.swift:186\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/AppOnboardingCoordinator.swift"},"region":{"startLine":186}}}],"partialFingerprints":{"codehealthFindingId/v1":"ad6a28f372dca1696c10303cd3eaf83ad29ddc0ab1a2a056e06ddb3c21f8a39f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 3): Wikipedia/Code/ColumnarCollectionViewController.swift:510-518 | Wikipedia/Code/NewsViewController.swift:260-268 | Wikipedia/Code/OnThisDayViewController.swift:265-273 \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 all 3 call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ColumnarCollectionViewController.swift:510\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ColumnarCollectionViewController.swift"},"region":{"startLine":510}}}],"partialFingerprints":{"codehealthFindingId/v1":"9ab4e036bb4be05b34ff5e4a54d7f9b714d4c2cdf4cbe52e0b4f6855a02505e5"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 3): Wikipedia/Code/EditSaveViewController.swift:125-133 | Wikipedia/Code/TalkPageReplyComposeContentView.swift:375-383 | Wikipedia/Code/TalkPageTopicComposeViewController.swift:476-484 \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 all 3 call sites, so a change lands once. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060Wikipedia/Code/TalkPageTopicComposeViewController.swift:486\u0060 calls \u0060Styles\u0060 and \u0060Wikipedia/Code/TalkPageReplyComposeContentView.swift:385\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/EditSaveViewController.swift"},"region":{"startLine":125}}}],"partialFingerprints":{"codehealthFindingId/v1":"9faf2274b62af07adb3934abc825bfe74ed4c79f9b4a5245db6fa40f9c8f14a6"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 3): Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift:232-240 | Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift:244-252 | Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift:259-267 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift:232\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift"},"region":{"startLine":232}}}],"partialFingerprints":{"codehealthFindingId/v1":"3faa3d20d3ba9b41e689e71dea031e4826fb389f4da22264981f98d9482ec53a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/WMFActivityTabCustomizeViewModel.swift:103-111 | WMFComponents/Sources/WMFComponents/Components/Settings/Storage and Syncing/WMFStorageAndSyncingSettingsViewModel.swift:16-24 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/WMFActivityTabCustomizeViewModel.swift"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"8e5a792db55bc45be927f1041c47018b0759a60db04e0d7c6997fef14351a6f8"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift:432-440 | WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift:497-505 \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":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":432}}}],"partialFingerprints":{"codehealthFindingId/v1":"281986c6ca8070d752a5d8d86ecbd9c6c909b00aac3bf7162188b7b107910619"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): Wikipedia/Code/APIURLComponentsBuilder.swift:79-87 | Wikipedia/Code/APIURLComponentsBuilder.swift:91-99 \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. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/APIURLComponentsBuilder.swift"},"region":{"startLine":79}}}],"partialFingerprints":{"codehealthFindingId/v1":"3b0f0c265df2b68c84753fceee26cb025c1fb6e6436b6d6c90f5169bb07ad10a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): Wikipedia/Code/BaseExploreFeedSettingsViewController.swift:42-50 | Wikipedia/Code/FeedCardSettingsViewController.swift:6-14 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/BaseExploreFeedSettingsViewController.swift:42\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/BaseExploreFeedSettingsViewController.swift"},"region":{"startLine":42}}}],"partialFingerprints":{"codehealthFindingId/v1":"830b3c09c079188a14b2d94a5032cfa8f910ef88473bcd34ed9dff73bd3c06b4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): Wikipedia/Code/DiffFetcher.swift:50-58 | Wikipedia/Code/GlobalUserInfoFetcher.swift:16-27 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DiffFetcher.swift\u0060 and \u0060Wikipedia/Code/GlobalUserInfoFetcher.swift\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 43 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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffFetcher.swift:50\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping (Result\u003CString, Error\u003E) -\u003E Void\u0060 in one and \u0060@escaping ((Result\u003CInt, Error\u003E) -\u003E Void)\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffFetcher.swift"},"region":{"startLine":50}}}],"partialFingerprints":{"codehealthFindingId/v1":"7d9904d2d15b40dc11fd129d526b6f3b8dd8d3964d6277c6632e8a98daaf7e35"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): Wikipedia/Code/DiffHeaderExtendedView.swift:34-42 | Wikipedia/Code/DiffHeaderView.swift:20-28 \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":"Wikipedia/Code/DiffHeaderExtendedView.swift"},"region":{"startLine":34}}}],"partialFingerprints":{"codehealthFindingId/v1":"f1479868c5498478addbbb67822d19f9e4952d347535792e62dcde1611211a44"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): Wikipedia/Code/PageHistoryViewController.swift:191-199 | Wikipedia/Code/PageHistoryViewController.swift:229-237 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/PageHistoryViewController.swift:191\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/PageHistoryViewController.swift"},"region":{"startLine":191}}}],"partialFingerprints":{"codehealthFindingId/v1":"3b2414a628636db44a47f158b0fdb991bc1f9a35ad92c6e191b686bdac293251"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): Wikipedia/Code/SavedAllArticlesCoordinator.swift:198-208 | Wikipedia/Code/WhichCameFirstCoordinator.swift:375-383 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/SavedAllArticlesCoordinator.swift:198\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/SavedAllArticlesCoordinator.swift"},"region":{"startLine":198}}}],"partialFingerprints":{"codehealthFindingId/v1":"82336e292a1d968c955256fa76a57dbbdc6c545f5a9531322e9d845ed3011627"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): Wikipedia/Code/SavedArticlesFetcher.swift:205-213 | Wikipedia/Code/SavedArticlesFetcher.swift:257-265 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/SavedArticlesFetcher.swift:205\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/SavedArticlesFetcher.swift"},"region":{"startLine":205}}}],"partialFingerprints":{"codehealthFindingId/v1":"36d753171f403769c4e44114392111c1bbb69f935550fc682e47d84eefd0690e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7\u20139 lines \u00D7 2): Wikipedia/Code/SettingsCoordinator.swift:113-121 | Wikipedia/Code/WMFAppViewController\u002BExtensions.swift:1334-1340 \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":"Wikipedia/Code/SettingsCoordinator.swift"},"region":{"startLine":113}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c3c5a3ca384978b022df356b00cc8fc920ae91738802321061e36db633d0635"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 3): WMF Framework/MWKDataStore\u002BLanguageVariantMigration.swift:115-123 | WMF Framework/MWKDataStore\u002BLanguageVariantMigration.swift:127-135 | WMF Framework/MWKDataStore\u002BLanguageVariantMigration.swift:138-147 \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. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060WMF Framework/MWKDataStore\u002BLanguageVariantMigration.swift:127\u0060 calls \u0060NSPredicate\u0060 and \u0060WMF Framework/MWKDataStore\u002BLanguageVariantMigration.swift:138\u0060 does not \u2014 after which the two agree again for 5 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/MWKDataStore\u002BLanguageVariantMigration.swift"},"region":{"startLine":115}}}],"partialFingerprints":{"codehealthFindingId/v1":"854a80ed4a92c323ac9b7cac9183ccec19f53193f175715493fc9248e262c69a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 6): WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsViewModel.swift:56-63 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsViewModel.swift:65-72 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsViewModel.swift:74-81 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsViewModel.swift:83-90 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/WMFHomeFeedForYouSettingsViewModel.swift:51-58 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/WMFHomeFeedForYouSettingsViewModel.swift:60-67 \u2014 there are 6 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 6 sites; resolving a subset leaves the remainder to drift apart. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsViewModel.swift:56\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsViewModel.swift"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"4a917dbe02d15902d8bad27499cbf891f80e516555f0f9725a6a9529f718ce84"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 4): Wikipedia/Code/ArticleLocationCollectionViewController.swift:219-226 | Wikipedia/Code/ColumnarCollectionViewController.swift:508-515 | Wikipedia/Code/NewsViewController.swift:258-265 | Wikipedia/Code/OnThisDayViewController.swift:263-270 \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 all 4 call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ArticleLocationCollectionViewController.swift:219\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleLocationCollectionViewController.swift"},"region":{"startLine":219}}}],"partialFingerprints":{"codehealthFindingId/v1":"b4ae9fabac7ccb217157fbba8c5e25cccdcdeda20cf9615c87e99b296e1c644a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 4): Wikipedia/Code/DiffFetcher.swift:51-58 | Wikipedia/Code/DiffFetcher.swift:200-209 | Wikipedia/Code/DiffFetcher.swift:244-253 | Wikipedia/Code/GlobalUserInfoFetcher.swift:17-27 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DiffFetcher.swift\u0060 and \u0060Wikipedia/Code/GlobalUserInfoFetcher.swift\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 43 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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffFetcher.swift:51\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping (Result\u003CString, Error\u003E) -\u003E Void\u0060 in one and \u0060@escaping (Result\u003CWMFPageHistoryRevision, Error\u003E) -\u003E Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffFetcher.swift"},"region":{"startLine":51}}}],"partialFingerprints":{"codehealthFindingId/v1":"cc3a35eb56c90b750c2baa72fc26643ede02487b9ccbc07429218d687158eff0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 4): Wikipedia/Code/DiffFetcher.swift:143-151 | Wikipedia/Code/DiffFetcher.swift:203-210 | Wikipedia/Code/DiffFetcher.swift:247-254 | Wikipedia/Code/GlobalUserInfoFetcher.swift:20-28 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DiffFetcher.swift\u0060 and \u0060Wikipedia/Code/GlobalUserInfoFetcher.swift\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 43 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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffFetcher.swift:143\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping ((Result\u003CWMFPageHistoryRevision, Error\u003E) -\u003E Void)\u0060 in one and \u0060@escaping (Result\u003CWMFPageHistoryRevision, Error\u003E) -\u003E Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffFetcher.swift"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"22eebb4e0b10c8bcdf0a8a515c86d23ec13c0ef9016b8acb241d867114b9b527"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift:64-72 | WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift:97-105 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFCategoriesDataController.swift:24-31 \u2014 there are 3 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 3 sites; resolving a subset leaves the remainder to drift apart. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift:64\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"e1df6a41e2a20a6dc06c060a830684e757280aa4512fc6382fab0a3ea1a35853"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): WMF Framework/SharedContainerCacheStore.swift:15-22 | WMF Framework/SharedContainerCacheStore.swift:29-36 | WMF Framework/SharedContainerCacheStore.swift:41-48 \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":"WMF Framework/SharedContainerCacheStore.swift"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"4b15bbf2cf25ebd1fb151064ba6018e7178cfc582f15e7193cd210f3d78c41d3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): Wikipedia/Code/DiffListChangeViewModel.swift:240-247 | Wikipedia/Code/DiffListContextViewModel.swift:167-174 | Wikipedia/Code/DiffListUneditedViewModel.swift:45-52 \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 all 3 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffListChangeViewModel.swift"},"region":{"startLine":240}}}],"partialFingerprints":{"codehealthFindingId/v1":"ff2ad9ca303a34a191b9f3d7c8db085e158d9190ed301337a87e1dd1cb579d8d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): Wikipedia/Code/Advanced Settings/InsertMediaImagePositionSettingsViewController.swift:61-68 | Wikipedia/Code/Advanced Settings/InsertMediaImageSizeSettingsViewController.swift:101-108 | Wikipedia/Code/Advanced Settings/InsertMediaImageTypeSettingsViewController.swift:76-83 \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 all 3 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/Advanced Settings/InsertMediaImagePositionSettingsViewController.swift"},"region":{"startLine":61}}}],"partialFingerprints":{"codehealthFindingId/v1":"1ab276e301d97def89c06aa3efd7c62c6897caaf97444d1cbc741c678dd1de4f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/TimelineViewModel.swift:47-54 | WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/TimelineViewModel.swift:92-99 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/TimelineViewModel.swift:47\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/TimelineViewModel.swift"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"a9206b86406a6ba7ee0c92a82c24b868829f53b6d6e64a00e8b7a31051286f55"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Shared/Buttons/CloseButtons.swift:155-162 | WMFComponents/Sources/WMFComponents/Components/Shared/Buttons/CloseButtons.swift:169-176 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Shared/Buttons/CloseButtons.swift:155\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Shared/Buttons/CloseButtons.swift"},"region":{"startLine":155}}}],"partialFingerprints":{"codehealthFindingId/v1":"d57a8a8927629e24a7354799e408dce852334037538b8e9e928dd416ffb07e2d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7\u20138 lines \u00D7 2): Wikipedia/Code/ArticleViewController\u002BDonationReminder.swift:253-260 | Wikipedia/Code/DonationReminderSetupCoordinator.swift:138-144 \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":"Wikipedia/Code/ArticleViewController\u002BDonationReminder.swift"},"region":{"startLine":253}}}],"partialFingerprints":{"codehealthFindingId/v1":"d74d149e328f304dc8fdfac38ce2119954a2097fcf909bf8ab0166ff2d028e84"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): WMF Framework/ArticleCacheResourceDBWriting.swift:37-44 | WMF Framework/ArticleCacheResourceDBWriting.swift:64-71 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/ArticleCacheResourceDBWriting.swift:37\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also register a scope-exit action (a \u0060defer\u0060-style statement) that runs when the function holding them returns: moved into a called unit it would run when THAT unit returns instead \u2014 before the caller uses what it releases \u2014 so keep the registration at the call site and extract only the work around it, or have the extracted unit hand the resource back for the caller to register. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping (Result\u003C[ArticleFetcher.MediaListItem], ArticleCacheDBWriterError\u003E) -\u003E Void\u0060 in one and \u0060@escaping (Result\u003C[URL], ArticleCacheDBWriterError\u003E) -\u003E Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/ArticleCacheResourceDBWriting.swift"},"region":{"startLine":37}}}],"partialFingerprints":{"codehealthFindingId/v1":"58749bbe550f104580423f744161fc0f37610698bc4edec503c2474eae283ce6"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): WMF Framework/CacheDBWriterHelper.swift:81-88 | WMF Framework/CacheDBWriterHelper.swift:92-99 \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. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/CacheDBWriterHelper.swift"},"region":{"startLine":81}}}],"partialFingerprints":{"codehealthFindingId/v1":"92761556fe6e1b30317a6c0bbfdf394c8fbf69c622b13625f144a59e9acdffb1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): WMF Framework/PageNamespace.swift:78-85 | Wikipedia/Code/NotificationsCenterAction.swift:103-110 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/PageNamespace.swift:78\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/PageNamespace.swift"},"region":{"startLine":78}}}],"partialFingerprints":{"codehealthFindingId/v1":"b4ff23a65fbeb9b51471391c5cff7195fff235c95086fdc317dea684963571b7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): WMF Framework/Widget/WidgetController.swift:37-44 | WMF Framework/Widget/WidgetController.swift:53-60 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/Widget/WidgetController.swift:37\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Widget/WidgetController.swift"},"region":{"startLine":37}}}],"partialFingerprints":{"codehealthFindingId/v1":"7337240f0eeb05123fe020cc161e2a93bd8e3f5825d9fd13b6085d39a61c428b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/ActivityTabViewController.swift:869-876 | Wikipedia/Code/TabsOverviewCoordinator.swift:44-51 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ActivityTabViewController.swift:869\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":869}}}],"partialFingerprints":{"codehealthFindingId/v1":"d92a55676e9713c3e99dd33c0b3ed68391edeffb829994add8db35caf57971e2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/BaseExploreFeedSettingsViewController.swift:65-72 | Wikipedia/Code/FeedCardSettingsViewController.swift:31-38 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/BaseExploreFeedSettingsViewController.swift:65\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/BaseExploreFeedSettingsViewController.swift"},"region":{"startLine":65}}}],"partialFingerprints":{"codehealthFindingId/v1":"08f790abd1ef887e6142a6a2dbdf4cd9062a7738c22c3afc414bf0d512f443ce"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/DiffContainerViewController.swift:1031-1040 | Wikipedia/Code/PageHistoryViewController.swift:817-824 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffContainerViewController.swift:1031\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":1031}}}],"partialFingerprints":{"codehealthFindingId/v1":"2e4814167b0510e522a5e16c742a8aa5e3ecb79ed3a4f0f46e4084431407ae3e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7\u20138 lines \u00D7 2): Wikipedia/Code/DiffFetcher.swift:193-200 | Wikipedia/Code/WikidataFetcher.swift:41-47 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffFetcher.swift:193\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffFetcher.swift"},"region":{"startLine":193}}}],"partialFingerprints":{"codehealthFindingId/v1":"af36cca6de4987ac4438f48df5aed96b43d6bb2eb0f71506d297c56063ca41ed"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/PageHistoryCountsView.swift:29-36 | Wikipedia/Code/PageHistoryCountsViewController.swift:26-33 \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":"Wikipedia/Code/PageHistoryCountsView.swift"},"region":{"startLine":29}}}],"partialFingerprints":{"codehealthFindingId/v1":"08187a561c006ab49978998ecbb6d2b9b5f3dd9959325aa644bbbbe01a1ca7ae"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/TalkPageFetcher.swift:190-197 | Wikipedia/Code/TalkPageFetcher.swift:213-220 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/TalkPageFetcher.swift:190\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageFetcher.swift"},"region":{"startLine":190}}}],"partialFingerprints":{"codehealthFindingId/v1":"ffe62c5a2f88abcb4487b7fc47d28c319d3f6251381580df2704c99e06f4f34c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/TalkPageFindInPageSearchController.swift:59-66 | Wikipedia/Code/TalkPageFindInPageSearchController.swift:73-80 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/TalkPageFindInPageSearchController.swift:59\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageFindInPageSearchController.swift"},"region":{"startLine":59}}}],"partialFingerprints":{"codehealthFindingId/v1":"4c51094553b6663f367b5123f3da4f37e72da3a4fff643fd080cafc73f45231e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/TalkPageViewController.swift:1205-1212 | Wikipedia/Code/TalkPageViewController.swift:1292-1299 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/TalkPageViewController.swift:1205\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageViewController.swift"},"region":{"startLine":1205}}}],"partialFingerprints":{"codehealthFindingId/v1":"53fb0b007ea6009a2b543f3539d3590a62ed6467090432686d7a62fd112f3019"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 3): WMFComponents/Sources/WMFComponents/Components/Shared/Project Icons/WMFProjectIconView.swift:31-37 | WMFComponents/Sources/WMFComponents/Components/Shared/Project Icons/WMFProjectIconView.swift:40-46 | WMFComponents/Sources/WMFComponents/Components/Shared/Project Icons/WMFProjectIconView.swift:48-54 \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":"WMFComponents/Sources/WMFComponents/Components/Shared/Project Icons/WMFProjectIconView.swift"},"region":{"startLine":31}}}],"partialFingerprints":{"codehealthFindingId/v1":"8fabcccf721ef1899ae652d1589acd57a37a858079edbb7e2927fad42f5a275b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5\u20137 lines \u00D7 3): Wikipedia/Code/DescriptionEditViewController.swift:157-163 | Wikipedia/Code/WMFAccountCreationViewController.swift:134-138 | Wikipedia/Code/WMFLoginViewController.swift:114-118 \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 all 3 call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DescriptionEditViewController.swift:157\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DescriptionEditViewController.swift"},"region":{"startLine":157}}}],"partialFingerprints":{"codehealthFindingId/v1":"20a257fb45b26dbeeedf880124d32e1592e9aa0533e573595dddc5fdccea6054"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 3): Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift:222-228 | Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift:235-241 | Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift:262-268 \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":"Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift"},"region":{"startLine":222}}}],"partialFingerprints":{"codehealthFindingId/v1":"69f48fbd4214e9893c8dc07ae5c528b5a10632462246931bb022ce73217f03a1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6\u20137 lines \u00D7 2): WMFData/Sources/WMFData/Data Controllers/Semantic Search/WMFSemanticSearchDataController\u002BResults.swift:39-44 | WMFData/Sources/WMFData/Data Controllers/Shared/UserContributionsDataController.swift:28-34 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Semantic Search/WMFSemanticSearchDataController\u002BResults.swift:39\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Semantic Search/WMFSemanticSearchDataController\u002BResults.swift"},"region":{"startLine":39}}}],"partialFingerprints":{"codehealthFindingId/v1":"151a827b06f839e421555b8cc2878a037c386a091f631ac2d05fa4932bd0fd82"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): WMF Framework/Fetcher.swift:110-116 | WMF Framework/Fetcher.swift:123-129 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/Fetcher.swift:110\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Fetcher.swift"},"region":{"startLine":110}}}],"partialFingerprints":{"codehealthFindingId/v1":"ae5a1295614c20646a8bc625d1792a030a48bd2a1fdad2da0fefb92409b96a3e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): WMF Framework/ReadingListsSyncOperation.swift:556-562 | WMF Framework/ReadingListsSyncOperation.swift:690-696 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/ReadingListsSyncOperation.swift:556\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also register a scope-exit action (a \u0060defer\u0060-style statement) that runs when the function holding them returns: moved into a called unit it would run when THAT unit returns instead \u2014 before the caller uses what it releases \u2014 so keep the registration at the call site and extract only the work around it, or have the extracted unit hand the resource back for the caller to register."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/ReadingListsSyncOperation.swift"},"region":{"startLine":556}}}],"partialFingerprints":{"codehealthFindingId/v1":"b4df5786dd4f127a4e2d393f35de142175a96617a3cc606cfebb471e451d3fff"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Widgets/Widgets/FeaturedArticleWidget.swift:82-88 | Widgets/Widgets/FeaturedArticleWidget.swift:98-104 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Widgets/Widgets/FeaturedArticleWidget.swift:82\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Widgets/Widgets/FeaturedArticleWidget.swift"},"region":{"startLine":82}}}],"partialFingerprints":{"codehealthFindingId/v1":"b140bad434a0da7fd229dd034ea8b654d4aeae811f0bfe4aee7abd8ccd2cd5c2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/AppOnboardingCoordinator.swift:244-250 | Wikipedia/Code/AppOnboardingCoordinator.swift:260-266 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/AppOnboardingCoordinator.swift:244\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/AppOnboardingCoordinator.swift"},"region":{"startLine":244}}}],"partialFingerprints":{"codehealthFindingId/v1":"8ef8ffda6165f2997b424a4b060054ef068643d79b3c12f71383f35f551f4f40"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6\u20137 lines \u00D7 2): Wikipedia/Code/AppOnboardingCoordinator.swift:251-256 | Wikipedia/Code/AppOnboardingCoordinator.swift:267-273 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/AppOnboardingCoordinator.swift:251\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/AppOnboardingCoordinator.swift"},"region":{"startLine":251}}}],"partialFingerprints":{"codehealthFindingId/v1":"362d1ab3893f525d740dc8fead38a8c833db8e4d28ab2e9f387cd3011483ddc8"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/ArticleFetcher.swift:182-188 | Wikipedia/Code/ArticleFetcher.swift:251-257 \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":"Wikipedia/Code/ArticleFetcher.swift"},"region":{"startLine":182}}}],"partialFingerprints":{"codehealthFindingId/v1":"35fa7e4013cd5ba4d32ef9e2841a8f4fae2cc07362474badf01ec7201a4fd420"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/ArticleRightAlignedImageCollectionViewCell.swift:56-62 | Wikipedia/Code/SavedArticlesCollectionViewCell.swift:158-164 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ArticleRightAlignedImageCollectionViewCell.swift:56\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleRightAlignedImageCollectionViewCell.swift"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"0438db20b60016e83383fa59ea87da34ba181ab4f16175d139d88701b87027fb"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/DiffContainerViewController.swift:1001-1007 | Wikipedia/Code/UIViewController\u002BExtensions.swift:98-105 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DiffContainerViewController.swift:1001\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":1001}}}],"partialFingerprints":{"codehealthFindingId/v1":"e9e73d779f895e54594be4a58a420ce197c16733263982bda3254d2c72b0528e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/EditNoticesFetcher.swift:31-37 | Wikipedia/Code/WMFAccountCreator.swift:140-150 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/EditNoticesFetcher.swift:31\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/EditNoticesFetcher.swift"},"region":{"startLine":31}}}],"partialFingerprints":{"codehealthFindingId/v1":"47cd9a12749e71a7a04d20e75866d9ecd73557e2f9fefd703c169ebfcb552a41"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 5): WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift:64-72 | WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift:97-105 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFCategoriesDataController.swift:24-31 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFPageTopicsDataController.swift:248-254 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFPageViewsDataController.swift:247-252 \u2014 there are 5 copies across 4 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 5 sites; resolving a subset leaves the remainder to drift apart. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift:64\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"cce4d740733b7e510d9d250016bbfdeb92bdf47eae9b6539add3626d4bcd5ac9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (1\u20136 lines \u00D7 4): Wikipedia/Code/ActivityTabViewController.swift:562-570 | Wikipedia/Code/ExploreViewController.swift:1732-1737 | Wikipedia/Code/HelpViewController.swift:139-139 | Wikipedia/Code/YearInReviewCoordinator.swift:122-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 all 4 call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ActivityTabViewController.swift:562\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":562}}}],"partialFingerprints":{"codehealthFindingId/v1":"9a04b7b1d526215e1d208b887d7a27ad2312e173fd96088f529a54b48bc64f60"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Base/WMFCanvasViewController.swift:38-43 | WMFComponents/Sources/WMFComponents/Base/WMFCanvasViewController.swift:51-56 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Base/WMFCanvasViewController.swift:38\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Base/WMFCanvasViewController.swift"},"region":{"startLine":38}}}],"partialFingerprints":{"codehealthFindingId/v1":"ec9da858c33417b6ab64bf7cb8e143a3d2ef99d16f099b45365a1e51aeae9eb1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewController.swift:56-61 | WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewController.swift:89-94 \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. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewController.swift:64\u0060 calls \u0060logWatchlistUserDidTapUserButton\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewController.swift:96\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewController.swift"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"90a207dcfb8ca4ba56bbe0a92044a7e3eea334ed69859c28f66274668677f33e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsViewModel.swift:92-97 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/WMFHomeFeedForYouSettingsViewModel.swift:69-74 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsViewModel.swift:92\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Home/Community/WMFHomeFeedCommunitySettingsViewModel.swift"},"region":{"startLine":92}}}],"partialFingerprints":{"codehealthFindingId/v1":"43fa527992f11f1251f4cdc2057d2d93e09828d0f02be4541ceda5b291bc98ca"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): WMFData/Sources/WMFData/Data Controllers/Shared/WMFUserImpactDataController.swift:94-99 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFUserImpactDataController.swift: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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Data Controllers/Shared/WMFUserImpactDataController.swift:94\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Shared/WMFUserImpactDataController.swift"},"region":{"startLine":94}}}],"partialFingerprints":{"codehealthFindingId/v1":"e29d7168539f9906f7b468726e27c8c26f659fcc3d354400df583ce2e571372a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/DonateFunnel.swift:511-516 | Wikipedia/Code/DonateFunnel.swift:552-557 \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. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DonateFunnel.swift"},"region":{"startLine":511}}}],"partialFingerprints":{"codehealthFindingId/v1":"a2dc6300402977d875ec0efd61756ac3d1aa2f95e470fdc4644399cbc3ef25dc"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5\u20136 lines \u00D7 2): Wikipedia/Code/AppViewControllerTipWrapper.swift:52-56 | Wikipedia/Code/WMFAppViewControllerTipWrapper.swift:41-46 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/AppViewControllerTipWrapper.swift:52\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/AppViewControllerTipWrapper.swift"},"region":{"startLine":52}}}],"partialFingerprints":{"codehealthFindingId/v1":"b05bf21f3d058ed16ea1c59b33fc633e05d090ac228f42e37674d6f707fee263"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/ArticlePlaceView.swift:254-259 | Wikipedia/Code/ArticlePlaceView.swift:481-486 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ArticlePlaceView.swift:254\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticlePlaceView.swift"},"region":{"startLine":254}}}],"partialFingerprints":{"codehealthFindingId/v1":"b0b19f7bb0eb47476e4a19c990f798e41032e9e72c7df6f4d469c04c7bac04ae"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/BaseExploreFeedSettingsViewController.swift:54-59 | Wikipedia/Code/FeedCardSettingsViewController.swift:26-31 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/BaseExploreFeedSettingsViewController.swift:54\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/BaseExploreFeedSettingsViewController.swift"},"region":{"startLine":54}}}],"partialFingerprints":{"codehealthFindingId/v1":"d685bbe6fc4721a0c197a7f81524174496ec4a79a0737fd357605a7c00c4b87f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/DiffListChangeViewModel.swift:71-76 | Wikipedia/Code/DiffListChangeViewModel.swift:109-114 \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":"Wikipedia/Code/DiffListChangeViewModel.swift"},"region":{"startLine":71}}}],"partialFingerprints":{"codehealthFindingId/v1":"f3c767add1c5398e5e78e31585bf2d08a8bab942d4434091f8a545a267c05c77"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/ExploreViewController.swift:1040-1045 | Wikipedia/Code/ExploreViewController.swift:1057-1063 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ExploreViewController.swift:1040\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":1040}}}],"partialFingerprints":{"codehealthFindingId/v1":"b22f8ffe5517bbb9ea07352974f5804ac166da2240e506521e392a21142f134f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/PlaceSearch.swift:126-131 | Wikipedia/Code/PlaceSearch.swift:163-168 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/PlaceSearch.swift:126\u0060 it runs out through the closing brace of the declaration holding it and carries on into the declaration that follows \u2014 the window is the tail of one member plus the head of the next, so no call can be substituted for those exact lines, and the smallest declaration that contains all of them is the type they sit in. The repeated unit is the member each site sits in: where those members\u0027 bodies are the same, move one whole member to the shared location and have the others delegate to it; where the copies are a run of near-identical overloads or wrappers that differ only in their signatures, the repetition IS the run \u2014 a one-line delegation has no helper inside it to lift \u2014 so generate the run from the set it enumerates, or accept it and keep each member\u0027s own documentation with it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/PlaceSearch.swift"},"region":{"startLine":126}}}],"partialFingerprints":{"codehealthFindingId/v1":"a7716829fbaab9cafc7191806e401d34084d1d49db9cc7bc4429aa7f2e6596ab"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/PlacesViewController.swift:1316-1321 | Wikipedia/Code/PlacesViewController.swift:1999-2004 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/PlacesViewController.swift:1316\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":1316}}}],"partialFingerprints":{"codehealthFindingId/v1":"82d038dd0c5b55a3f4a857c3b53fc5e674cbe67e1c4f99f46a77814602f89aa2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/ReadingListsCollectionViewCell.swift:210-215 | Wikipedia/Code/SavedArticlesCollectionViewCell.swift:212-217 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/ReadingListsCollectionViewCell.swift:210\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ReadingListsCollectionViewCell.swift"},"region":{"startLine":210}}}],"partialFingerprints":{"codehealthFindingId/v1":"34cadbf29f461d95c5faeb35606e02df61e042948d555e804d04f219b747ddd4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5\u20136 lines \u00D7 2): Wikipedia/Code/UIViewController\u002BExtensions.swift:53-58 | Wikipedia/Code/UIViewController\u002BExtensions.swift:69-73 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/UIViewController\u002BExtensions.swift:53\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/UIViewController\u002BExtensions.swift"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"3cb45ecefe426f54f788698ab85873aa2d7c08aae7f7967c307c1a17f3fb2b27"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/WMFAccountCreationViewController.swift:172-177 | Wikipedia/Code/WMFLoginViewController.swift:460-465 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAccountCreationViewController.swift:172\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAccountCreationViewController.swift"},"region":{"startLine":172}}}],"partialFingerprints":{"codehealthFindingId/v1":"63e40e6f8bc60d4cbe904b6cfaf351ca33dc78c7662e1fb48dd19f62fdb93908"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/WMFAccountCreationViewController.swift:212-217 | Wikipedia/Code/WMFLoginViewController.swift:471-476 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAccountCreationViewController.swift:212\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAccountCreationViewController.swift"},"region":{"startLine":212}}}],"partialFingerprints":{"codehealthFindingId/v1":"6fee621850e209f155f5537dd0229ef6c261ce5f4f4ac1087021782efbab0264"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/WMFAccountCreationViewController.swift:640-645 | Wikipedia/Code/WMFLoginViewController.swift:590-595 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/WMFAccountCreationViewController.swift:640\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAccountCreationViewController.swift"},"region":{"startLine":640}}}],"partialFingerprints":{"codehealthFindingId/v1":"f4b790c29af12f43f6240996084167fecd57f629ca93bdd4bde2158de94a0f2c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): WMF Framework/Collection\u002BAsyncMap.swift:30-35 | WMF Framework/Collection\u002BAsyncMap.swift:48-53 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMF Framework/Collection\u002BAsyncMap.swift:30\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Collection\u002BAsyncMap.swift"},"region":{"startLine":30}}}],"partialFingerprints":{"codehealthFindingId/v1":"4f0a857579ccaafa139560f841ca881c7020f7d1c70326913c605f79110e7184"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 10): Wikipedia/Code/DiffContainerViewController.swift:1003-1007 | Wikipedia/Code/NotificationsCenterViewController.swift:614-618 | Wikipedia/Code/ReadingListsAlertController.swift:111-115 | Wikipedia/Code/ThanksGiving.swift:87-91 | Wikipedia/Code/UIViewController\u002BExtensions.swift:101-105 | Wikipedia/Code/UIViewController\u002BExtensions.swift:141-145 | Wikipedia/Code/UIViewController\u002BExtensions.swift:172-176 | Wikipedia/Code/UIViewController\u002BExtensions.swift:196-200 | Wikipedia/Code/UIViewController\u002BExtensions.swift:217-221 | Wikipedia/Code/UIViewController\u002BExtensions.swift:230-234 \u2014 there are 10 copies across 5 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 10 sites; resolving a subset leaves the remainder to drift apart."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DiffContainerViewController.swift"},"region":{"startLine":1003}}}],"partialFingerprints":{"codehealthFindingId/v1":"9e3e47373c0983c6205f48655fef3ab7e125182f3fdf23318e80ba374ee8438f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 3): Wikipedia/Code/ColumnarCollectionViewController.swift:135-139 | Wikipedia/Code/TalkPageTopicComposeViewController.swift:428-432 | Wikipedia/Code/TalkPageViewController.swift:309-313 \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 all 3 call sites, so a change lands once. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ColumnarCollectionViewController.swift"},"region":{"startLine":135}}}],"partialFingerprints":{"codehealthFindingId/v1":"9902d69f061c413a7daff335d576509daa224ce3a5954f80077121f0cbb21696"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Base/WMFCanvasViewController.swift:44-48 | WMFComponents/Sources/WMFComponents/Base/WMFCanvasViewController.swift:57-61 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Base/WMFCanvasViewController.swift:44\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Base/WMFCanvasViewController.swift"},"region":{"startLine":44}}}],"partialFingerprints":{"codehealthFindingId/v1":"b8d2443783add64a0bad976e9d5fb4846f5117650280d6233f0128384f0e8892"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (2\u20135 lines \u00D7 4): WMFData/Sources/WMFData/Utility/WMFWikitextUtils.swift:243-244 | WMFData/Sources/WMFData/Utility/WMFWikitextUtils.swift:245-249 | WMFData/Sources/WMFData/Utility/WMFWikitextUtils.swift:251-255 | WMFData/Sources/WMFData/Utility/WMFWikitextUtils.swift:256-259 \u2014 all 4 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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFData/Utility/WMFWikitextUtils.swift:243\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060WMFData/Sources/WMFData/Utility/WMFWikitextUtils.swift:255\u0060 calls \u0060NSRegularExpression\u0060, \u0060matches\u0060, \u0060NSRange\u0060 and \u0060WMFData/Sources/WMFData/Utility/WMFWikitextUtils.swift:244\u0060 does not \u2014 after which the two agree again for 4 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Utility/WMFWikitextUtils.swift"},"region":{"startLine":243}}}],"partialFingerprints":{"codehealthFindingId/v1":"ba644e04b3c9723f8d3b1ebd96620db4a7aaaa35e0bede6db47a81066b868b62"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/ActivityTabViewController.swift:582-586 | Wikipedia/Code/SavedViewController.swift:325-329 \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":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":582}}}],"partialFingerprints":{"codehealthFindingId/v1":"408ce3f862767151792eeb203775bdce74d895f600a5990e821d0bc96d4fe2aa"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/AppOnboardingCoordinator.swift:119-123 | Wikipedia/Code/AppOnboardingCoordinator.swift:142-146 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/AppOnboardingCoordinator.swift:119\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/AppOnboardingCoordinator.swift"},"region":{"startLine":119}}}],"partialFingerprints":{"codehealthFindingId/v1":"80e051425c211e7702a98278b884330a645a43a4f97ff2ac0dd94c706a584ecb"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/AppOnboardingCoordinator.swift:329-333 | Wikipedia/Code/WhichCameFirstCoordinator.swift:417-421 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/AppOnboardingCoordinator.swift:329\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/AppOnboardingCoordinator.swift"},"region":{"startLine":329}}}],"partialFingerprints":{"codehealthFindingId/v1":"71949579b09a825f02d325f5750aff3cd8a0c3ff123bc1898f5f1cb765e796b7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/DescriptionWelcomePageViewController.swift:114-118 | Wikipedia/Code/WMFWelcomePageViewController.swift:140-144 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DescriptionWelcomePageViewController.swift\u0060 and \u0060Wikipedia/Code/WMFWelcomePageViewController.swift\u0060 as WHOLE FILES: this scan already matched 9 separate duplicated blocks between them, totalling at least 84 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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DescriptionWelcomePageViewController.swift:114\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DescriptionWelcomePageViewController.swift"},"region":{"startLine":114}}}],"partialFingerprints":{"codehealthFindingId/v1":"6fa532d225fc7ebd97e2a6c2f7cb44ec12224f10984cf01100ad9590a4034db9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/DescriptionWelcomePageViewController.swift:132-136 | Wikipedia/Code/WMFWelcomePageViewController.swift:174-178 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DescriptionWelcomePageViewController.swift\u0060 and \u0060Wikipedia/Code/WMFWelcomePageViewController.swift\u0060 as WHOLE FILES: this scan already matched 9 separate duplicated blocks between them, totalling at least 84 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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/DescriptionWelcomePageViewController.swift:132\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DescriptionWelcomePageViewController.swift"},"region":{"startLine":132}}}],"partialFingerprints":{"codehealthFindingId/v1":"938f1416998909c5a72175236c3e50f7a875e441864054b0156b7523a6b1c49b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/EditorViewController.swift:850-854 | Wikipedia/Code/EditorViewController.swift:861-865 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/EditorViewController.swift:850\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/EditorViewController.swift"},"region":{"startLine":850}}}],"partialFingerprints":{"codehealthFindingId/v1":"e71cf9b3571d0ed728af70d30a133e72e1c7830908287cf07d3c6ea5b17aecc9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/Session.swift:527-531 | Wikipedia/Code/Session.swift:535-539 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/Session.swift:527\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/Session.swift"},"region":{"startLine":527}}}],"partialFingerprints":{"codehealthFindingId/v1":"5ebadd536f5d63e7b3e8ad8aac76b988a84501c9d9f7c7aa65cc24ac247e0b57"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/TalkPageFindInPageSearchController.swift:48-52 | Wikipedia/Code/TalkPageFindInPageSearchController.swift:89-93 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/TalkPageFindInPageSearchController.swift:48\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageFindInPageSearchController.swift"},"region":{"startLine":48}}}],"partialFingerprints":{"codehealthFindingId/v1":"c2f2fba683ccdf6a473b9d51f6b5ce313efaed8ba371d3dbdad08f1e946e8fb7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/WMFAccountCreationViewController.swift:635-639 | Wikipedia/Code/WMFLoginViewController.swift:585-589 \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":"Wikipedia/Code/WMFAccountCreationViewController.swift"},"region":{"startLine":635}}}],"partialFingerprints":{"codehealthFindingId/v1":"dd71c05e4b4c6d8acb9f2c115cb3cfb9cc99cd54cf6a28b33759ff2b24bff860"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Widgets/Widgets/URL\u002BWidgetSource.swift:8-13 | Widgets/Widgets/URL\u002BWidgetSource.swift:21-25 \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":"Widgets/Widgets/URL\u002BWidgetSource.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"5e9a048312488a74cf2b41318ab6cf6ea94428fe3b22ff5ebe81562cf6258e16"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): WMF Framework/SetupButton.swift:6-20 | WMF Framework/SetupView.swift:6-20 \u2014 before extracting anything, compare \u0060WMF Framework/SetupButton.swift\u0060 and \u0060WMF Framework/SetupView.swift\u0060 as WHOLE FILES: 83% of the shorter file\u0027s lines also appear in the other, so this reads as one file having been copied from the other rather than as a helper waiting to be extracted. The 1 duplicated block(s) this scan matched between them are fragments of that copy, not the extent of it \u2014 treat the file pair as the unit. 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":"WMF Framework/SetupButton.swift"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"d559d142615a9ac14c85bf530b6b4ed1753c0c4081d9e3ce0e8da347f9d64bfe"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 4): WMFComponents/Sources/WMFComponents/Base/Component Base Classes/WMFComponentHostingController.swift:49-53 | WMFComponents/Sources/WMFComponents/Base/Component Base Classes/WMFComponentNavigationController.swift:97-101 | WMFComponents/Sources/WMFComponents/Base/Component Base Classes/WMFComponentView.swift:37-41 | WMFComponents/Sources/WMFComponents/Base/Component Base Classes/WMFComponentViewController.swift:43-47 \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 all 4 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Base/Component Base Classes/WMFComponentHostingController.swift"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"3681d913b14711748b08473d71a8eb0c34cf50bdc3fb93993921c43a929206ab"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Shared/Feature Announcement/WMFFeatureAnnouncementView.swift:54-59 | WMFComponents/Sources/WMFComponents/Components/Temp Accounts/WMFTempAccountsSheetView.swift:21-26 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Shared/Feature Announcement/WMFFeatureAnnouncementView.swift"},"region":{"startLine":54}}}],"partialFingerprints":{"codehealthFindingId/v1":"b3a7b16cca9c1f756b17ad9742731415bbabeb7e03c5e2db70f6dd50f7329f95"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/Base/WMFEditorToolbarButton.swift:51-55 | WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/WMFEditorToolbarNavigatorButton.swift:47-51 \u2014 before extracting anything, compare \u0060WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/Base/WMFEditorToolbarButton.swift\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/WMFEditorToolbarNavigatorButton.swift\u0060 as WHOLE FILES: 85% of the shorter file\u0027s lines also appear in the other, so this reads as one file having been copied from the other rather than as a helper waiting to be extracted. The 2 duplicated block(s) this scan matched between them are fragments of that copy, not the extent of it \u2014 treat the file pair as the unit. The two sit in different directories, so one cannot simply be deleted in favour of the other while both are reached separately: hoist the shared part into a location both already depend on and have each file call it, and retire whichever file turns out to have no caller of its own left. Extracting one helper per block leaves the fork in place. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/Base/WMFEditorToolbarButton.swift"},"region":{"startLine":51}}}],"partialFingerprints":{"codehealthFindingId/v1":"021172bf23490e3189018d6cd6f97cdb25726ac9d688716832e15f18b16f2b94"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsViewModel.swift:15-22 | WMFComponents/Sources/WMFComponents/Components/Settings/Push Notifications/WMFPushNotificationsSettingsViewModel.swift:16-23 | WMFComponents/Sources/WMFComponents/Components/Suggested Edits/Image Recommendations/WMFImageRecommendationsViewModel.swift:52-59 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 3 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 3 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Account/WMFAccountSettingsViewModel.swift"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"5ba6d7a3489e9a695ff736f76f75abe36ce6495f4e825078ae9264ae821b9395"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 3): WMFComponents/Sources/WMFComponents/Components/Settings/Year In Review/WMFYearInReviewSettingsViewModel.swift:12-16 | WMFComponents/Sources/WMFComponents/Components/Shared/Error View/WMFErrorViewModel.swift:11-15 | WMFData/Sources/WMFData/Utility/WMFWikitextUtils.swift:12-16 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 3 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 3 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Year In Review/WMFYearInReviewSettingsViewModel.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"84818b442f473ac3e4c9395a0529d7b3b42807c4ad9e12f300a3825b6a5bb457"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 3): WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift:9-14 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFCategoriesDataController.swift:13-20 | WMFData/Sources/WMFData/Data Controllers/Shared/WMFPageTopicsDataController.swift:13-18 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 3 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 3 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Home/WMFPageInterestDataController.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"bb3d52d76832d5147eced4510a47f313ffdb0e7f5d02e125aed22109635957a6"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/WMFYearInReviewDonateCountSlideDataController.swift:24-29 | WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/YearInReviewEditCountSlideDataController.swift:23-28 \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":"WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/WMFYearInReviewDonateCountSlideDataController.swift"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"2b718bea0e1f57901ceaa5c9e4a6f0f28c7d2c98f529aaf64355474b2fde30a9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 3): WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/WMFYearInReviewMostReadDateSlideDataController.swift:18-22 | WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/YearInReviewReadCountSlideDataController.swift:19-23 | WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/YearInReviewTopArticlesSlideDataController.swift:19-23 \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 all 3 call sites, so a change lands once. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/YearInReviewTopArticlesSlideDataController.swift:26\u0060 calls \u0060WMFPageViewsDataController\u0060 and \u0060WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/WMFYearInReviewMostReadDateSlideDataController.swift:26\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/WMFYearInReviewMostReadDateSlideDataController.swift"},"region":{"startLine":18}}}],"partialFingerprints":{"codehealthFindingId/v1":"a99719276bb3474b1ca235ec467db7f9f7dd1e70d9a032f0ba8896c684102869"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/WMFYearInReviewSaveCountSlideDataController.swift:38-48 | WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/YearInReviewEditCountSlideDataController.swift:43-53 \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":"WMFData/Sources/WMFData/Data Controllers/Year In Review/Slide Data Controllers/WMFYearInReviewSaveCountSlideDataController.swift"},"region":{"startLine":38}}}],"partialFingerprints":{"codehealthFindingId/v1":"af5c26b65f95d70d20ed931569c446b4dc6d5518742d06e0304191fe20ba9a95"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): ContinueReadingWidget/WMFTodayContinueReadingWidgetViewController.swift:87-92 | Wikipedia/Code/WMFArticlePreviewViewController.swift:64-69 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"ContinueReadingWidget/WMFTodayContinueReadingWidgetViewController.swift"},"region":{"startLine":87}}}],"partialFingerprints":{"codehealthFindingId/v1":"b9d77839a96d7614e718b1d82c6d9f44cc8f78bdc1ae05ad7f53fe525c6020a3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 3): WMF Framework/ActionButton.swift:24-30 | Wikipedia/Code/CollectionViewCell.swift:197-203 | Wikipedia/Code/SizeThatFitsReusableView.swift:113-119 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 3 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 3 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/ActionButton.swift"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"08967189dd2bf5aa9c533abc9cbe68d13fd2de921b884db07e3354d1f7394207"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Widgets/Widgets/LockscreenSearchWidget.swift:43-48 | Widgets/Widgets/SearchWidget.swift:45-50 \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":"Widgets/Widgets/LockscreenSearchWidget.swift"},"region":{"startLine":43}}}],"partialFingerprints":{"codehealthFindingId/v1":"25a7e7b639b99ab3e6cf3c9b9e71f80966b019136455e079759c14fc44f37e59"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16 lines \u00D7 2): Wikipedia/Code/ActivityTabViewController.swift:301-316 | Wikipedia/Code/SavedViewController.swift:67-82 \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. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":301}}}],"partialFingerprints":{"codehealthFindingId/v1":"de0cd4bae9a3293995cbf69931f5ad1b404fb024981e76cdd3744ec374e7459c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/ActivityTabViewController.swift:717-724 | Wikipedia/Code/InsertMediaSettingsViewController.swift:372-379 \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":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":717}}}],"partialFingerprints":{"codehealthFindingId/v1":"04aed8a9f19cb4e883626cb38a83399a50fca52f406b8557582bb1afbd619c13"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 3): Wikipedia/Code/ActivityTabViewController.swift:811-820 | Wikipedia/Code/SavedViewController.swift:705-714 | Wikipedia/Code/SearchViewController.swift:661-666 \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 all 3 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":811}}}],"partialFingerprints":{"codehealthFindingId/v1":"5d57332b59eb79e85ef2c8e354844b85e7f517f05bd3517631dc818bd8baa2e0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/AppViewControllerTipWrapper.swift:20-26 | Wikipedia/Code/WMFAppViewControllerTipWrapper.swift:19-25 \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. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/AppViewControllerTipWrapper.swift"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"56b2c85d272a69e7663ae44b1fd3cb95680640683d80e68a71785886eb3ae705"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): Wikipedia/Code/AppearanceSettingsViewController.swift:374-382 | Wikipedia/Code/Temp Accounts/TempAccountsSettingsViewController.swift:90-98 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/AppearanceSettingsViewController.swift"},"region":{"startLine":374}}}],"partialFingerprints":{"codehealthFindingId/v1":"ece7eb8bee11d3ad10edda7504d4af06b00d996e9fc854fdf886602bcbd17a84"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): Wikipedia/Code/ArticleViewController.swift:114-128 | Wikipedia/Code/PlacesViewController.swift:419-433 \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. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":114}}}],"partialFingerprints":{"codehealthFindingId/v1":"92c0fd99210af731ff8518b91202e91cdcc03aa51ad34c0c095da9f0185b7bc6"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 4): Wikipedia/Code/ArticleViewController.swift:1781-1785 | Wikipedia/Code/ExploreViewController.swift:1988-1992 | Wikipedia/Code/HomeViewController.swift:457-461 | Wikipedia/Code/PlacesViewController.swift:2625-2629 \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 all 4 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":1781}}}],"partialFingerprints":{"codehealthFindingId/v1":"b94db033c8a10c0386372f4b22e3d508bffc669c67b64f08e370b78932172b94"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): Wikipedia/Code/BaseExploreFeedSettingsViewController.swift:313-321 | Wikipedia/Code/Temp Accounts/TempAccountsSettingsViewController.swift:144-152 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/BaseExploreFeedSettingsViewController.swift"},"region":{"startLine":313}}}],"partialFingerprints":{"codehealthFindingId/v1":"6cf34772b61c2fc0944b4224fab62af0e328383c136600992b9f6c6ba2d0a5ac"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): Wikipedia/Code/ColumnarCollectionViewController.swift:229-237 | Wikipedia/Code/InsertMediaSearchResultsCollectionViewController.swift:184-192 \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":"Wikipedia/Code/ColumnarCollectionViewController.swift"},"region":{"startLine":229}}}],"partialFingerprints":{"codehealthFindingId/v1":"ed8de52e49bba6755c1e45c2d09b2f0dd4139184dced611272b8a0fdf83ebe6f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/ArticleViewController\u002BArticlePreviewing.swift:19-25 | Wikipedia/Code/ColumnarCollectionViewController.swift:546-552 \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":"Wikipedia/Code/ArticleViewController\u002BArticlePreviewing.swift"},"region":{"startLine":19}}}],"partialFingerprints":{"codehealthFindingId/v1":"d3e642cb78e9d6fd8f62d9c57c4e51d3bf5cfa9fd8399ee94232e91d4832df92"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 5): Wikipedia/Code/ArticleViewController\u002BEditing.swift:365-371 | Wikipedia/Code/DescriptionEditViewController.swift:40-46 | Wikipedia/Code/TempAccountSheetCoordinator.swift:38-44 | Wikipedia/Code/TempAccountSheetCoordinator.swift:45-51 | Wikipedia/Code/TempAccountSheetCoordinator.swift:53-59 \u2014 there are 5 copies across 3 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 5 sites; resolving a subset leaves the remainder to drift apart. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleViewController\u002BEditing.swift"},"region":{"startLine":365}}}],"partialFingerprints":{"codehealthFindingId/v1":"7fd05925580db2af1f745f9c8a2ac288137c8476fa48cc3d0dc2d72a9fd770f2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/DescriptionWelcomeContainerViewController.swift:21-26 | Wikipedia/Code/WMFWelcomeContainerViewController.swift:28-33 \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":"Wikipedia/Code/DescriptionWelcomeContainerViewController.swift"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"c8d337a882bb246a5a7b8fc7fdea7227acd013f9a0f101b8eff1d7d4871971b0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/DescriptionWelcomeContainerViewController.swift:53-58 | Wikipedia/Code/WMFWelcomeContainerViewController.swift:79-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":"Wikipedia/Code/DescriptionWelcomeContainerViewController.swift"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"fa13b5dd7bbc1b86cc2fc110769a146a8f1ce46a4f4c3e35385fb97491a89ad6"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/DescriptionWelcomeInitialViewController.swift:7-13 | Wikipedia/Code/EmptyViewController.swift:30-39 \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":"Wikipedia/Code/DescriptionWelcomeInitialViewController.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"c3f8f66963d6a38dea60c19dea6fc377c2101954045d8cfb713eceaa0d8e86b2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/DescriptionWelcomePageViewController.swift:166-171 | Wikipedia/Code/WMFWelcomePageViewController.swift:243-248 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DescriptionWelcomePageViewController.swift\u0060 and \u0060Wikipedia/Code/WMFWelcomePageViewController.swift\u0060 as WHOLE FILES: this scan already matched 9 separate duplicated blocks between them, totalling at least 84 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":"Wikipedia/Code/DescriptionWelcomePageViewController.swift"},"region":{"startLine":166}}}],"partialFingerprints":{"codehealthFindingId/v1":"e153cfdb48edafe0dedd9ac150af706b8b819fffe69ae99844116f5a6187989c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 3): Wikipedia/Code/DescriptionWelcomePageViewController.swift:173-178 | Wikipedia/Code/WMFReferencePageViewController.swift:162-167 | Wikipedia/Code/WMFWelcomePageViewController.swift:250-255 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DescriptionWelcomePageViewController.swift\u0060 and \u0060Wikipedia/Code/WMFWelcomePageViewController.swift\u0060 as WHOLE FILES: this scan already matched 9 separate duplicated blocks between them, totalling at least 84 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":"Wikipedia/Code/DescriptionWelcomePageViewController.swift"},"region":{"startLine":173}}}],"partialFingerprints":{"codehealthFindingId/v1":"00b266f3ed744acab6161964c7f773a5298c5e8760adec625a77a4a7480af2f0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 3): Wikipedia/Code/DescriptionWelcomePageViewController.swift:180-185 | Wikipedia/Code/WMFReferencePageViewController.swift:169-174 | Wikipedia/Code/WMFWelcomePageViewController.swift:257-262 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DescriptionWelcomePageViewController.swift\u0060 and \u0060Wikipedia/Code/WMFWelcomePageViewController.swift\u0060 as WHOLE FILES: this scan already matched 9 separate duplicated blocks between them, totalling at least 84 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":"Wikipedia/Code/DescriptionWelcomePageViewController.swift"},"region":{"startLine":180}}}],"partialFingerprints":{"codehealthFindingId/v1":"0ad2fa62876584cd9c911547e2b6661600b9ce0e3ee3a7cc5cca38606a4b37ee"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/DescriptionWelcomePageViewController.swift:187-191 | Wikipedia/Code/WMFWelcomePageViewController.swift:264-268 \u2014 before extracting anything, compare \u0060Wikipedia/Code/DescriptionWelcomePageViewController.swift\u0060 and \u0060Wikipedia/Code/WMFWelcomePageViewController.swift\u0060 as WHOLE FILES: this scan already matched 9 separate duplicated blocks between them, totalling at least 84 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":"Wikipedia/Code/DescriptionWelcomePageViewController.swift"},"region":{"startLine":187}}}],"partialFingerprints":{"codehealthFindingId/v1":"4a5ab94e9f3e878d6ea60d72d47301119658119a2f2061892fb3579be1451a8e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/DescriptionWelcomePanelViewController.swift:78-83 | Wikipedia/Code/WMFWelcomePanelViewController.swift:111-116 \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. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060Wikipedia/Code/DescriptionWelcomePanelViewController.swift:85\u0060 calls \u0060performNextButtonAction\u0060 and \u0060Wikipedia/Code/WMFWelcomePanelViewController.swift:117\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DescriptionWelcomePanelViewController.swift"},"region":{"startLine":78}}}],"partialFingerprints":{"codehealthFindingId/v1":"ca8cad50de889605dac02761e000a0dc282148ada367c67e15aa23126461da6f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 3): Wikipedia/Code/EraseSavedArticlesView.swift:12-18 | Wikipedia/Code/InsertMediaImageInfoView.swift:19-25 | Wikipedia/Code/InsertMediaSettingsButtonView.swift:16-22 \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 all 3 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/EraseSavedArticlesView.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"9013d3589152e352cda0bab7a86eb376888e504c33bf0474edea8a682289f6bf"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/Advanced Settings/InsertMediaCustomImageSizeSettingTableViewCell.swift:10-17 | Wikipedia/Code/InsertMediaSettingsTextTableViewCell.swift:25-32 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/Advanced Settings/InsertMediaCustomImageSizeSettingTableViewCell.swift"},"region":{"startLine":10}}}],"partialFingerprints":{"codehealthFindingId/v1":"c323f1d4ec7ca83f1f5d74b7a7f7ceb8c553ffec52d719b578d5128dfade03a3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/NotificationsCenterViewController.swift:982-988 | Wikipedia/Code/TalkPageViewController.swift:535-541 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060Wikipedia/Code/TalkPageViewController.swift:535\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NotificationsCenterViewController.swift"},"region":{"startLine":982}}}],"partialFingerprints":{"codehealthFindingId/v1":"5f3355bc7e0e88a42e674dc13803ceb28cc8034541d950bd357645666f3e14ab"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/PageHistoryCountsView.swift:39-45 | Wikipedia/Code/PageHistoryCountsViewController.swift:36-42 \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":"Wikipedia/Code/PageHistoryCountsView.swift"},"region":{"startLine":39}}}],"partialFingerprints":{"codehealthFindingId/v1":"30c8641d6282611c8bd7b6abce9534805185df0bc11b1fd2f3e894c10f688726"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/ReadingListEntryCollectionViewController.swift:29-34 | Wikipedia/Code/ReadingListsViewController.swift:37-42 \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. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ReadingListEntryCollectionViewController.swift"},"region":{"startLine":29}}}],"partialFingerprints":{"codehealthFindingId/v1":"e83df267bd2548e1352192ec038c9683041019e239a99038d6c3a0bd3a65c246"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/ReadingListEntryCollectionViewController.swift:227-231 | Wikipedia/Code/ReadingListsViewController.swift:364-368 \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":"Wikipedia/Code/ReadingListEntryCollectionViewController.swift"},"region":{"startLine":227}}}],"partialFingerprints":{"codehealthFindingId/v1":"2110225bd66055fbc59f90a9594a878c7982ab53c7b6229320ab0525f24ef519"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/ReadingListEntryCollectionViewController.swift:546-552 | Wikipedia/Code/ReadingListsViewController.swift:551-557 \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":"Wikipedia/Code/ReadingListEntryCollectionViewController.swift"},"region":{"startLine":546}}}],"partialFingerprints":{"codehealthFindingId/v1":"f273b8b8ecb32218870e1c012ba7ab2010a043c031f30e31baf814941a6879c4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/TalkPageCellCommentView.swift:176-182 | Wikipedia/Code/TalkPageCellTopicView.swift:440-446 \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":"Wikipedia/Code/TalkPageCellCommentView.swift"},"region":{"startLine":176}}}],"partialFingerprints":{"codehealthFindingId/v1":"38be389d107f7d18f071d451765812c228f1be734f7cde8372dcfed004269334"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 4): Wikipedia/Code/TalkPageCellCommentView.swift:205-211 | Wikipedia/Code/TalkPageCellTopicView.swift:484-490 | Wikipedia/Code/TalkPageCoffeeRollView.swift:113-119 | Wikipedia/Code/TalkPageReplyComposeContentView.swift:428-434 \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 all 4 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageCellCommentView.swift"},"region":{"startLine":205}}}],"partialFingerprints":{"codehealthFindingId/v1":"67f78afe8560dd5f3ebbb1d85aa110dd2d81cecfd404fb009105241e5ebfa20f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): Wikipedia/Code/TalkPageReplyComposeContentView.swift:349-359 | Wikipedia/Code/TalkPageTopicComposeViewController.swift:250-260 \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":"Wikipedia/Code/TalkPageReplyComposeContentView.swift"},"region":{"startLine":349}}}],"partialFingerprints":{"codehealthFindingId/v1":"b3e9a4033848a161ea8ebba4a54bab419d0731eea9b66198cab1b091d6f6c1d4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/TalkPageTopicReplyOnboardingHostingController.swift:46-50 | Wikipedia/Code/VanishAccountWarningViewHostingViewController.swift:58-62 \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":"Wikipedia/Code/TalkPageTopicReplyOnboardingHostingController.swift"},"region":{"startLine":46}}}],"partialFingerprints":{"codehealthFindingId/v1":"4f0743adebe3680cacd0b1d7efdc36b68f9e6588067769947daed861699103bc"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/TalkPageTopicReplyOnboardingView.swift:41-48 | Wikipedia/Code/VanishAccountWarningView.swift:41-48 \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. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060Wikipedia/Code/VanishAccountWarningView.swift:52\u0060 calls \u0060replacingOccurrences\u0060 and \u0060Wikipedia/Code/TalkPageTopicReplyOnboardingView.swift:50\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageTopicReplyOnboardingView.swift"},"region":{"startLine":41}}}],"partialFingerprints":{"codehealthFindingId/v1":"1e67baad97e8cfbc14c7ec0f1f5c9f2a5cdc21ba3b9b2cb1ff574b5d71bc8dfe"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/ArticleViewController\u002BEditing.swift:359-363 | Wikipedia/Code/TalkPageViewController.swift:1442-1446 \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":"Wikipedia/Code/ArticleViewController\u002BEditing.swift"},"region":{"startLine":359}}}],"partialFingerprints":{"codehealthFindingId/v1":"c5a30ce85e7906274f0c2b846b6cd3eacb7369a471ef822feb8e641144088596"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/WMFAccountCreationViewController.swift:280-287 | Wikipedia/Code/WMFLoginViewController.swift:197-203 \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":"Wikipedia/Code/WMFAccountCreationViewController.swift"},"region":{"startLine":280}}}],"partialFingerprints":{"codehealthFindingId/v1":"5ed1d31fda11805a85d1cbb925780bcea5e73ff9fc3f97b83a17964d41000413"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/WMFAccountCreationViewController.swift:328-334 | Wikipedia/Code/WMFLoginViewController.swift:161-167 \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":"Wikipedia/Code/WMFAccountCreationViewController.swift"},"region":{"startLine":328}}}],"partialFingerprints":{"codehealthFindingId/v1":"61b29d27cb4b9a31cbffca34b3ae773ea5eb4505dadfc468740b97906a7e208e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/WMFAccountCreator.swift:10-17 | Wikipedia/Code/WMFAccountLoginLogoutFetcher.swift:10-17 \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":"Wikipedia/Code/WMFAccountCreator.swift"},"region":{"startLine":10}}}],"partialFingerprints":{"codehealthFindingId/v1":"b0456494833d733d533e5d76cf6025a223ff6f95e0812003b11ec3522b8399fe"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 3): Wikipedia/Code/Advanced Settings/InsertMediaAdvancedSettingsViewController.swift:114-123 | Wikipedia/Code/Advanced Settings/InsertMediaImagePositionSettingsViewController.swift:72-81 | Wikipedia/Code/Advanced Settings/InsertMediaImageSizeSettingsViewController.swift:112-121 \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 all 3 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/Advanced Settings/InsertMediaAdvancedSettingsViewController.swift"},"region":{"startLine":114}}}],"partialFingerprints":{"codehealthFindingId/v1":"afd73416207fbce9293219516a5e2146c991f25e3ffbe06e9356308ae888543c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): Wikipedia/Code/Advanced Settings/InsertMediaImagePositionSettingsViewController.swift:110-119 | Wikipedia/Code/Advanced Settings/InsertMediaImageTypeSettingsViewController.swift:129-138 \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":"Wikipedia/Code/Advanced Settings/InsertMediaImagePositionSettingsViewController.swift"},"region":{"startLine":110}}}],"partialFingerprints":{"codehealthFindingId/v1":"818badf3762cbf77e01b3a2211ed02d41478f6b6ebba68ca0a5cef0242daecc7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/Advanced Settings/InsertMediaImagePositionSettingsViewController.swift:121-125 | Wikipedia/Code/Advanced Settings/InsertMediaImageTypeSettingsViewController.swift:140-144 \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":"Wikipedia/Code/Advanced Settings/InsertMediaImagePositionSettingsViewController.swift"},"region":{"startLine":121}}}],"partialFingerprints":{"codehealthFindingId/v1":"821857842d264a89eb08c9605c5dc462eb97964cade543e2b57560a3efc42ad5"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Home/WMFForYouView.swift:54-61 | WMFComponents/Sources/WMFComponents/Components/Home/WMFHomeView.swift:24-31 \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":"WMFComponents/Sources/WMFComponents/Components/Home/WMFForYouView.swift"},"region":{"startLine":54}}}],"partialFingerprints":{"codehealthFindingId/v1":"6b111ff5035252657e85307fb651bda9c88ae5ed536e8050d6e085c569e167e1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/Cards/WMFWhichCameFirstCardViewModel.swift:82-86 | WMFData/Sources/WMFData/Models/Shared/WMFPageInterest.swift:13-17 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/Cards/WMFWhichCameFirstCardViewModel.swift"},"region":{"startLine":82}}}],"partialFingerprints":{"codehealthFindingId/v1":"3011de749889d85faa3bed2db26a3a144ffadfad7e4e77a9957380e82842c825"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/WMFHomeFeedWhatsDrivingSettingsViewController.swift:8-12 | WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/Your Interests/WMFHomeFeedInterestsSettingsViewController.swift:11-15 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060viewModel\u0060 to \u0060WMFHomeFeedWhatsDrivingSettingsViewModel\u0060 in one and \u0060WMFHomeFeedInterestsSettingsViewModel\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/WMFHomeFeedWhatsDrivingSettingsViewController.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"a9727c2fb13f262b42afa1ba017cc80cd5be1912918a5d23c7c2c4530dbd5514"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift:850-855 | WMFData/Sources/WMFData/Models/Shared/WMFWhichCameFirstGameState.swift:33-38 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift"},"region":{"startLine":850}}}],"partialFingerprints":{"codehealthFindingId/v1":"9b2cdb28ba53a20f85ac541e26d54b5022b673a823a3bdcccec9a2f03c003412"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): WMFData/Sources/WMFData/Data Controllers/Shared/WMFOnThisDayDataController.swift:183-187 | WMFData/Sources/WMFData/Models/Shared/WMFPageTopic.swift:26-30 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Shared/WMFOnThisDayDataController.swift"},"region":{"startLine":183}}}],"partialFingerprints":{"codehealthFindingId/v1":"d7c195c4af0fc8e6a73b53d889822bd3f3faf21caa9c848d275a9609dae100f5"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Widgets/Widgets/LockscreenSearchWidget.swift:29-34 | Widgets/Widgets/SearchWidget.swift:31-36 \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. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060configuration\u0060 to \u0060LockscreenSearchWidgetConfiguration = LockscreenSearchWidgetConfiguration()\u0060 in one and \u0060SearchWidgetConfiguration = SearchWidgetConfiguration()\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Widgets/Widgets/LockscreenSearchWidget.swift"},"region":{"startLine":29}}}],"partialFingerprints":{"codehealthFindingId/v1":"5566c0d26440d07892a2f431925f51d871d67d53ccaea3213b74d3c4f20d815c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Widgets/Widgets/LockscreenSearchWidget.swift:65-69 | Widgets/Widgets/SearchWidget.swift:67-71 \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. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping (Timeline\u003CLockscreenSearchEntry\u003E) -\u003E Void\u0060 in one and \u0060@escaping (Timeline\u003CSearchEntry\u003E) -\u003E Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Widgets/Widgets/LockscreenSearchWidget.swift"},"region":{"startLine":65}}}],"partialFingerprints":{"codehealthFindingId/v1":"e13b46d4603b4ddcb4dc41d4b4708a214c546ff2074940b504ea10beaca27436"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Widgets/Widgets/OnThisDayWidget.swift:58-62 | Widgets/Widgets/TopReadWidget.swift:156-160 \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. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060completion\u0060 to \u0060@escaping (OnThisDayEntry) -\u003E Void\u0060 in one and \u0060@escaping (TopReadEntry) -\u003E Void\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Widgets/Widgets/OnThisDayWidget.swift"},"region":{"startLine":58}}}],"partialFingerprints":{"codehealthFindingId/v1":"e8eb34d18984233991c8d266adc8056236042b71da8338ee1dd03b2f9258c4a9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/ArticleViewController.swift:960-966 | Wikipedia/Code/SinglePageWebViewController.swift:289-295 \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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":960}}}],"partialFingerprints":{"codehealthFindingId/v1":"a4590a5cff1a63889359d6208e31ed7635db6f8f8f63dc50472ba57e4570e743"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/DescriptionWelcomeInitialViewController.swift:16-23 | Wikipedia/Code/WMFWelcomeInitialViewController.swift:10-17 \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":"Wikipedia/Code/DescriptionWelcomeInitialViewController.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"e0d5f7a020dea0e27dad83e105b65c3021e67544368b0331c152dda56613b206"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/EditNoticesViewController.swift:21-25 | Wikipedia/Code/TalkPageCoffeeRollViewController.swift:24-28 \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. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060viewModel\u0060 to \u0060EditNoticesViewModel\u0060 in one and \u0060TalkPageCoffeeRollViewModel\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/EditNoticesViewController.swift"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"cb6b8f4295946ff9f691bab536765959bb2b43ee8a0bbad213056639813fb210"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Wikipedia/Code/InsertMediaSettingsImageView.swift:47-53 | Wikipedia/Code/InsertMediaSettingsTextTableViewCell.swift:64-70 \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":"Wikipedia/Code/InsertMediaSettingsImageView.swift"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"bae50da7ae5362085172f4a5308b1e70826617c93712519d05557fdbd89ec22b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/NotificationsCenterDetailViewController.swift:19-24 | Wikipedia/Code/TalkPageViewController.swift:162-167 \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. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060viewModel\u0060 to \u0060NotificationsCenterDetailViewModel\u0060 in one and \u0060TalkPageViewModel\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NotificationsCenterDetailViewController.swift"},"region":{"startLine":19}}}],"partialFingerprints":{"codehealthFindingId/v1":"acf0e86b4a548a70c5fdd98cc9a4bcb684c1e2d150052e773e95d8795756906b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): Wikipedia/Code/WMFChangePasswordViewController.swift:59-66 | Wikipedia/Code/WMFForgotPasswordViewController.swift:62-69 \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":"Wikipedia/Code/WMFChangePasswordViewController.swift"},"region":{"startLine":59}}}],"partialFingerprints":{"codehealthFindingId/v1":"5bba6820f579bc89a422e36a269ecf9bbd2e879023af4e31ffca19c519910b83"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/Advanced Settings/InsertMediaImagePositionSettingsViewController.swift:24-28 | Wikipedia/Code/Advanced Settings/InsertMediaImageTypeSettingsViewController.swift:23-27 \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":"Wikipedia/Code/Advanced Settings/InsertMediaImagePositionSettingsViewController.swift"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"a7c11b33aacae4ff0ae7815bf78f8f19c0ca562fbb26a4ace9080f7b973154d9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewController.swift:73-85 | WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewController.swift:102-114 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewController.swift:73\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewController.swift:100\u0060 calls \u0060watchlistUserDidTapDiff\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewController.swift:72\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Watchlist/WMFWatchlistViewController.swift"},"region":{"startLine":73}}}],"partialFingerprints":{"codehealthFindingId/v1":"fe1ee08c00017f8456ef9cac4e198c343a18d6c56b131d123625604ad32e80b6"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): Widgets/Widgets/RandomWidget.swift:16-22 | Widgets/Widgets/RandomWidget.swift:24-30 \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":"Widgets/Widgets/RandomWidget.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"fb854edb8a87071c786284a4ad6992b96feb8e037f291a200d0d19dd60487c07"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): WMF Framework/TimelineView.swift:274-278 | WMF Framework/TimelineView.swift:280-284 \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":"WMF Framework/TimelineView.swift"},"region":{"startLine":274}}}],"partialFingerprints":{"codehealthFindingId/v1":"1d6758b2f31b310a440799933ce0f6f378482d817cabd21d0d066483c5e3cfcb"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/DiffListChangeCell.swift:139-143 | Wikipedia/Code/DiffListChangeCell.swift:168-172 \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":"Wikipedia/Code/DiffListChangeCell.swift"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"cc48a49151aeca2099b94a9ce3683d1424a61790915e5d0d56927484538110f0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): Wikipedia/Code/EditPreviewViewController.swift:73-78 | Wikipedia/Code/EditPreviewViewController.swift:81-86 \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. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/EditPreviewViewController.swift"},"region":{"startLine":73}}}],"partialFingerprints":{"codehealthFindingId/v1":"97a5cef5847b409af01636c02aa3d8077f075c7cef2c2f3307443cbed768cc1f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/ExploreCardViewController.swift:353-357 | Wikipedia/Code/ExploreCardViewController.swift:360-364 \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":"Wikipedia/Code/ExploreCardViewController.swift"},"region":{"startLine":353}}}],"partialFingerprints":{"codehealthFindingId/v1":"97d4c0f88990207b28b7ef214434f78f269046807be45bb18eae738154e5b4af"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): Wikipedia/Code/HomeFeedSettingsCoordinator.swift:84-88 | Wikipedia/Code/HomeFeedSettingsCoordinator.swift:169-173 \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":"Wikipedia/Code/HomeFeedSettingsCoordinator.swift"},"region":{"startLine":84}}}],"partialFingerprints":{"codehealthFindingId/v1":"f26ee72ed51b1409f4411644b92776218fc6a975e3d04fcef30db420953a97cc"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (5 members, 50\u002B identical tokens): WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:8-20 | WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:22-33 | WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:35-46 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:73-87 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:108-117 \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":"WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"c7d0b250c5a09a5b6fe12177a604ec80a9224cb4d8aaa6f13387e4887ccac081"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (4 members, 50\u002B identical tokens): WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift:171-186 | WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift:188-203 | WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:108-123 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:153-168 \u2014 These 4 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 4 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 4 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift"},"region":{"startLine":171}}}],"partialFingerprints":{"codehealthFindingId/v1":"f1f2d133a95af72f9952078501acd1b1d6842ca755627e235d2f33fdf00dca2c"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (4 members, 50\u002B identical tokens): WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:7-16 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:18-27 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:59-71 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:97-106 \u2014 These 4 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 4 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 4 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"b11129e5f9677f7bde127618f65b62db600d5fc98a45342455e17e07a7704410"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (22 lines \u00D7 2): WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift:44-65 | WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift:87-108 \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":"WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift"},"region":{"startLine":44}}}],"partialFingerprints":{"codehealthFindingId/v1":"346969aececbab245c831628c33017619cb092cc88fa3f00459b116a1016da49"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (21 lines \u00D7 2): WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:176-196 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:198-218 \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. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift"},"region":{"startLine":176}}}],"partialFingerprints":{"codehealthFindingId/v1":"2256cd626c7a13931351f07e7f2f843fab417fb320f0c35799a623055ee3a6ef"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201315 lines \u00D7 4): WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift:173-186 | WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift:190-203 | WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:109-123 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:155-168 \u2014 before extracting anything, compare \u0060WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift\u0060 and \u0060WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift\u0060 as WHOLE FILES: this scan already matched 3 separate duplicated blocks between them, totalling at least 38 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. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift"},"region":{"startLine":173}}}],"partialFingerprints":{"codehealthFindingId/v1":"37bcc62cf22def1a769e0b7d74ee9b1491045dfbf621b453c57fce2399287825"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201315 lines \u00D7 3): WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift:156-169 | WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:92-106 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:138-151 \u2014 before extracting anything, compare \u0060WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift\u0060 and \u0060WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift\u0060 as WHOLE FILES: this scan already matched 3 separate duplicated blocks between them, totalling at least 38 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":"WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift"},"region":{"startLine":156}}}],"partialFingerprints":{"codehealthFindingId/v1":"63ccf05458401bfa2d0147b4a40f2501bbc116b3fab6e99ae4995374096c10eb"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:242-255 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:259-272 \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. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift"},"region":{"startLine":242}}}],"partialFingerprints":{"codehealthFindingId/v1":"6c20df6e7051ea5d5676be65a0831d3aeac2190c050957adaa4c9cc0f15efbbf"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6\u20138 lines \u00D7 4): WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:12-17 | WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:25-30 | WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:38-43 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:75-82 \u2014 before extracting anything, compare \u0060WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift\u0060 and \u0060WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 52 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. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"4b182de6bdfe281effbd266ffeb306db7f03e6f3428ce311fd2774e85988f6e3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7\u20138 lines \u00D7 4): WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:7-14 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:18-25 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:59-66 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:97-103 \u2014 all 4 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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:7\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"4aabf3a49759652643e544967a40dcac7d76444597324d3c041afa95d2cb5527"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift:147-154 | WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:83-90 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:129-136 \u2014 before extracting anything, compare \u0060WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift\u0060 and \u0060WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift\u0060 as WHOLE FILES: this scan already matched 3 separate duplicated blocks between them, totalling at least 38 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":"WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift"},"region":{"startLine":147}}}],"partialFingerprints":{"codehealthFindingId/v1":"7ae9ca152a471013b0fc3b28d99e969e0db1ff089a1d00d83d1ef84e24ac7354"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 5): WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:12-17 | WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:25-30 | WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift:38-43 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:75-80 | WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift:110-114 \u2014 before extracting anything, compare \u0060WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift\u0060 and \u0060WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 52 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. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFDataMocks/WMFMockGrowthTasksService.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"9e23ba99b3c3731a47027f738b7b284849db209caad8028e45b82021f92809c7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): WMFData/Sources/WMFDataMocks/WMFMockURLSession.swift:40-44 | WMFData/Sources/WMFDataMocks/WMFMockURLSession.swift:67-71 \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. Each matched range is the entire body of the declaration above it, so the region is already a complete unit: move that whole declaration to the shared location and have each site call it, rather than lifting the lines out of their bodies. Any \u0060return\u0060 inside it is the body\u0027s own exit and keeps its meaning in the moved unit."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFDataMocks/WMFMockURLSession.swift"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"9bfe60c96905e45929ea953f5c645813d2119d2c685339b1f68f3244a245616c"}},{"ruleId":"D5","level":"warning","message":{"text":"Off the main sequence: WMFNativeLocalizations: WMFNativeLocalizations: abstractness 0.00, instability 0.00, distance 1.00 \u2014 zone of pain \u2014 concrete and depended on by 1 project(s), so it\u0027s rigid to change."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"60435d2edb35209d23fc83d26a293b327297761cc1d87c0a7aa7614e0a09e392"}},{"ruleId":"D5","level":"warning","message":{"text":"Off the main sequence: WMFTestKitchen: WMFTestKitchen: abstractness 0.10, instability 0.00, distance 0.90 \u2014 zone of pain \u2014 concrete and depended on by 1 project(s), so it\u0027s rigid to change."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"85dac971b83b889847d17959a94e699c70d09c69bff59a136a3251a800a2eec2"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ExploreViewController (LCOM4 58): ExploreViewController\u0027s methods fall into 58 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 58 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"a7b7202a7bef0adc75afacb2b73cd9d6d74606221abc960ec1880d3a2d485ca7"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: UserDefaults (LCOM4 38): UserDefaults\u0027s methods fall into 38 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 38 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NSUserDefaults\u002BWMFApplicationDefaults.swift"},"region":{"startLine":35}}}],"partialFingerprints":{"codehealthFindingId/v1":"268dd30912631e142593808570c7b3a3b969938c8b239c955ba97f4227e0c941"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFAppViewController (LCOM4 26): WMFAppViewController\u0027s methods fall into 26 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 26 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":43}}}],"partialFingerprints":{"codehealthFindingId/v1":"392218cd85b12a1a063261cfac25147dafec0e0585014c5b3b029ddb4908325c"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: UIViewController (LCOM4 25): UIViewController\u0027s methods fall into 25 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 25 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/FundraisingAnnouncementPanel.swift"},"region":{"startLine":97}}}],"partialFingerprints":{"codehealthFindingId/v1":"22ecb047f220ccc861177ec7414139352459a605f48b2817792178adc6cf386e"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ArticleViewController (LCOM4 17): ArticleViewController\u0027s methods fall into 17 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 17 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":10}}}],"partialFingerprints":{"codehealthFindingId/v1":"cb22677a10159901e2af3329b2c1ac829cc11693ac6b6e4c2480346e3c442025"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: UIView (LCOM4 16): UIView\u0027s methods fall into 16 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 16 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/UIStackView\u002BSubviewVerification.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"d266d9eec40a326025d3e57eda6ee0d842d43c95816a2fd27ac4c423a2e266fb"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: Configuration (LCOM4 13): Configuration\u0027s methods fall into 13 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 13 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Configuration.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"b2a70ab619f088fee76f5d9575d592c557aa5a8d007fcb7032a48068fdfd9a6c"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: EditorViewController (LCOM4 13): EditorViewController\u0027s methods fall into 13 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 13 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/EditorViewController.swift"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"f5ee029a60c16f69b807af852b6e4f8705c33c6360f41879c63d58d7f8a12a40"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: OnThisDayViewController (LCOM4 13): OnThisDayViewController\u0027s methods fall into 13 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 13 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/OnThisDayViewController.swift"},"region":{"startLine":5}}}],"partialFingerprints":{"codehealthFindingId/v1":"73ff568a5e59132a75e02a65e8ecdef81b71c06515969f86a6b985ffc762497e"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: TalkPageViewController (LCOM4 13): TalkPageViewController\u0027s methods fall into 13 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 13 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageViewController.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"d74e31e1b3fd4978031ebe4c7eff996205e6a83b807d00208803f8bdd812755a"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSettingsViewController (LCOM4 12): WMFSettingsViewController\u0027s methods fall into 12 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 12 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Settings/WMFSettingsViewController.swift"},"region":{"startLine":5}}}],"partialFingerprints":{"codehealthFindingId/v1":"14a5c4cbbdac5134e42ca37932950346ecd32dafd9552e4732c599d7b1f3cd1f"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ColumnarCollectionViewController (LCOM4 12): ColumnarCollectionViewController\u0027s methods fall into 12 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 12 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ColumnarCollectionViewController.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"54e5ee4bf2f9a10404ecd8f44c9b3b9d135f93c44fc8fe21bc5835b46cb5bc8a"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: InsertMediaViewController (LCOM4 12): InsertMediaViewController\u0027s methods fall into 12 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 12 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/InsertMediaViewController.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"8702d5928777256584379b98edf510d7eb908a64a8114eac980f756ed736399f"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ReadingListsViewController (LCOM4 12): ReadingListsViewController\u0027s methods fall into 12 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 12 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ReadingListsViewController.swift"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"2154ff5bad1b39587822d09395c1b4b52842bc1bac32b728923e82c4d58897ed"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSearchResultsViewModel (LCOM4 11): WMFSearchResultsViewModel\u0027s methods fall into 11 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 11 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Search/Results/WMFSearchResultsViewModel.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"4c3b044abb7fa94d81dbb823b9f650f319d957d298d926cbe050f4b5c6ac13f8"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFActivityTabDataController (LCOM4 11): WMFActivityTabDataController\u0027s methods fall into 11 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 11 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Activity Tab/WMFActivityTabDataController.swift"},"region":{"startLine":3}}}],"partialFingerprints":{"codehealthFindingId/v1":"bc963b872ca044e345d7a770728064a4c49577c739b5b2339125c930c9116efd"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: NewsViewController (LCOM4 11): NewsViewController\u0027s methods fall into 11 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 11 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NewsViewController.swift"},"region":{"startLine":5}}}],"partialFingerprints":{"codehealthFindingId/v1":"7fcf4619c4b1e24adb484157c5810491a5afcc7877f1e3beda326c8028b0cce6"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: SavedViewController (LCOM4 11): SavedViewController\u0027s methods fall into 11 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 11 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/SavedViewController.swift"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"df25254056ffba0568acc5729a778bad388ea15711e4989377bcacc20c8db051"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFActivityTabViewController (LCOM4 10): WMFActivityTabViewController\u0027s methods fall into 10 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 10 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"bb0174081d37d17036077cdc8edb32cf298d5d89abb581d508df04044f050d07"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ArticleFetchedResultsViewController (LCOM4 10): ArticleFetchedResultsViewController\u0027s methods fall into 10 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 10 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleFetchedResultsViewController.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"67a3277e94d4a3505244a374c895f77fa8fd5c7472af0322df2dc1063ba852d4"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ExploreCardViewController (LCOM4 10): ExploreCardViewController\u0027s methods fall into 10 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 10 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ExploreCardViewController.swift"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"bd10e8757189346fcd71345c6bd878fc79afb62b421fbb87f6e9d104e81df53c"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: InsertMediaSettingsViewController (LCOM4 10): InsertMediaSettingsViewController\u0027s methods fall into 10 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 10 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/InsertMediaSettingsViewController.swift"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"6ea3eaa0076711601d88583534633a5cabab37a5a532b420f78500ff9b057c74"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ArticleFetcher (LCOM4 9): ArticleFetcher\u0027s methods fall into 9 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 9 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleFetcher.swift"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"9a1046968702e0cdf89db51355655e1e8b85dc6c81f343d1adc3d716fa598798"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ReadingListEntryCollectionViewController (LCOM4 9): ReadingListEntryCollectionViewController\u0027s methods fall into 9 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 9 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ReadingListEntryCollectionViewController.swift"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"73927c79a64231beefef3a1f02633c153f770c9af50d43fc14c55e4838b5ddad"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: SearchViewController (LCOM4 9): SearchViewController\u0027s methods fall into 9 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 9 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/SearchViewController.swift"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"0518a84077997901292be8d21270705372f6dea1d700d199126599588068ad0d"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: TabsOverviewCoordinator (LCOM4 9): TabsOverviewCoordinator\u0027s methods fall into 9 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 9 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TabsOverviewCoordinator.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"b8bf857ac8d1ac465b29288e283f224fc69fa843b857bb8738148a53ee3f1902"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: String (LCOM4 9): String\u0027s methods fall into 9 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 9 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/HasText.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"35ee8c981404497bec655bf9426ca6871285351aec14fdcce1e45d0d838e8999"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSourceEditorFormatterLink (LCOM4 8): WMFSourceEditorFormatterLink\u0027s methods fall into 8 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 8 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorFormatterLink.swift"},"region":{"startLine":13}}}],"partialFingerprints":{"codehealthFindingId/v1":"bac5d1b6d6f91274842f1de50e18e5715df4d804f977a4b1343cac0f8e626927"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ArticleURLListViewController (LCOM4 8): ArticleURLListViewController\u0027s methods fall into 8 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 8 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleURLListViewController.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"a713a8df4c88e89990739e2aeaa0c53e6c51a61d96547c4c825459e92ecb8d10"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: EditPreviewViewController (LCOM4 8): EditPreviewViewController\u0027s methods fall into 8 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 8 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/EditPreviewViewController.swift"},"region":{"startLine":17}}}],"partialFingerprints":{"codehealthFindingId/v1":"774e329f138472ecc4a982bb2e805f88dc444b90a44f131b8513b238c49967a3"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: PlacesViewController (LCOM4 8): PlacesViewController\u0027s methods fall into 8 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 8 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"f2c13e51b22cd135fb56f08faf858bc5a74ffc1b6ab721629af5260268cd2782"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: TalkPageTopicComposeViewController (LCOM4 8): TalkPageTopicComposeViewController\u0027s methods fall into 8 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 8 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageTopicComposeViewController.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"c083b3769f1a62a998937d3c8163152f104e5e36c47b5cb1eefb4661b61d7093"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: NSManagedObjectContext (LCOM4 8): NSManagedObjectContext\u0027s methods fall into 8 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 8 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/NSManagedObjectContext\u002BHistory.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"b1049fada0564664a319fa767eafc69ca012eff048ba90c348378bb9a06a6ed0"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ColumnarCollectionViewLayout (LCOM4 7): ColumnarCollectionViewLayout\u0027s methods fall into 7 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 7 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/ColumnarCollectionViewLayout.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"a9388a74b5d06fce8afe8a27044281f94647d46e4b7861d6990bd95f40b6ea45"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: AppearanceSettingsViewController (LCOM4 7): AppearanceSettingsViewController\u0027s methods fall into 7 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 7 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/AppearanceSettingsViewController.swift"},"region":{"startLine":52}}}],"partialFingerprints":{"codehealthFindingId/v1":"cd08336544755c6f449ce97a4a99b2e9378a3a30cdccaad4bca0e11e0fb0d1d4"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ArticleLocationCollectionViewController (LCOM4 7): ArticleLocationCollectionViewController\u0027s methods fall into 7 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 7 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleLocationCollectionViewController.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"4c87cc002037b42f4c46198e11caa2faa3bc1316f8572f1fa6ede93531fc061d"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: BaseExploreFeedSettingsViewController (LCOM4 7): BaseExploreFeedSettingsViewController\u0027s methods fall into 7 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 7 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/BaseExploreFeedSettingsViewController.swift"},"region":{"startLine":157}}}],"partialFingerprints":{"codehealthFindingId/v1":"140142313e6cc6a54606f04449b54e960f06718d1cb1ce91d66fb420db9773c9"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ReadingListDetailViewController (LCOM4 7): ReadingListDetailViewController\u0027s methods fall into 7 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 7 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ReadingListDetailViewController.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"8ff7d6c1037b630f7230b093ca09d4d85f348e0dd6369b1e2d8e64e72b16378c"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ReadingThemesControlsArticlePresenter (LCOM4 7): ReadingThemesControlsArticlePresenter\u0027s methods fall into 7 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 7 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ReadingThemesControlsProtocols.swift"},"region":{"startLine":96}}}],"partialFingerprints":{"codehealthFindingId/v1":"d154693cf4924276d2b2c434cdc05d6bd98556f53252da1f331cecc42ee002eb"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: SinglePageWebViewController (LCOM4 7): SinglePageWebViewController\u0027s methods fall into 7 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 7 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/SinglePageWebViewController.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"34570484b004c3fed37b85a598de4931a1212aab0ce1e6c10c787858b1cc8031"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: UITextView (LCOM4 7): UITextView\u0027s methods fall into 7 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 7 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/HasText.swift"},"region":{"startLine":60}}}],"partialFingerprints":{"codehealthFindingId/v1":"07e4639657e4dae1d3f0925882651c1430142848b37949ae89e2ad27048b89ff"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFComponentNavigationController (LCOM4 6): WMFComponentNavigationController\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Base/Component Base Classes/WMFComponentNavigationController.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"22776f58e0d090560cb154da57f30c56e0aee07505cdccae2f7396fdb6fbd1ed"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFActivityTabViewModel (LCOM4 6): WMFActivityTabViewModel\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabViewModel.swift"},"region":{"startLine":5}}}],"partialFingerprints":{"codehealthFindingId/v1":"baa5c56cac91be0c05b1cf205cfe6e8820dba502fb2c64b7a123009c65b17a4e"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSourceEditorFormatterList (LCOM4 6): WMFSourceEditorFormatterList\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorFormatterList.swift"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"0feea4dac0fd7883aa7e16225bee5d7086bfff5f895779e575008e0f193ecc03"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSemanticSearchDataController (LCOM4 6): WMFSemanticSearchDataController\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Semantic Search/WMFSemanticSearchDataController.swift"},"region":{"startLine":5}}}],"partialFingerprints":{"codehealthFindingId/v1":"e782bf7d12769a963f984e8c6a7b62b6d29eb14084f2c906b76a0c90a8239f19"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFMockBasicService (LCOM4 6): WMFMockBasicService\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFDataMocks/WMFMockBasicService.swift"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"d217e707d47d24c3284c03b38a98c623e9cc817bbb070ea256ec97f0a5dc8732"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFMockWatchlistMediaWikiService (LCOM4 6): WMFMockWatchlistMediaWikiService\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFDataMocks/WMFMockWatchlistMediaWikiService.swift"},"region":{"startLine":121}}}],"partialFingerprints":{"codehealthFindingId/v1":"a09ee7f43b934443562b0029db9b449d37ef33f722f57958dd391278e0efdec5"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: UserSession (LCOM4 6): UserSession\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/UserSession.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"d2cd1468a41236d6e48e083e8e4c12749719f3af77041a463119965324a70bfb"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: AppDelegate (LCOM4 6): AppDelegate\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/AppDelegate.swift"},"region":{"startLine":17}}}],"partialFingerprints":{"codehealthFindingId/v1":"7ed2d07f4e8fc7618c3bce08085c4777b13a2394183d7e3364cc354c003bc43a"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ArticleCollectionViewController (LCOM4 6): ArticleCollectionViewController\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleCollectionViewController.swift"},"region":{"startLine":5}}}],"partialFingerprints":{"codehealthFindingId/v1":"dad5d5852164bdaaec2f79b5da2b642359dc7dbaad827a2dfc2bbd738135dfe9"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ArticleWebMessagingController (LCOM4 6): ArticleWebMessagingController\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleWebMessagingController.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"0b7fb754752c3db3d35959567355c4b048ea27a2361fe2ed5a8627674b3f2329"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ExploreFeedSettingsViewController (LCOM4 6): ExploreFeedSettingsViewController\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ExploreFeedSettingsViewController.swift"},"region":{"startLine":164}}}],"partialFingerprints":{"codehealthFindingId/v1":"bcecad6df8c9086c47f209563a3f1097e175b1bbe0f19f2f1f6029bcec5e7580"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: SavedAllArticlesCoordinator (LCOM4 6): SavedAllArticlesCoordinator\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/SavedAllArticlesCoordinator.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"cce6adc90b75db4d4828d904b841e8a2a67ed2d83f9c59b6c929a00d019ae7f2"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: SceneDelegate (LCOM4 6): SceneDelegate\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/SceneDelegate.swift"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"62a6dbcda76ace8d3b1fbdeb2f77f1a03b7c94ace3869dd29999bb59a3b36b8f"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: YearInReviewCoordinator (LCOM4 6): YearInReviewCoordinator\u0027s methods fall into 6 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 6 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/YearInReviewCoordinator.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"68fc9af607b48308421fb16736941b6f6fbeef7dbed29aa11e56cb2794ffac9b"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFArticleTabsViewModel (LCOM4 5): WMFArticleTabsViewModel\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Article Tabs/WMFArticleTabsViewModel.swift"},"region":{"startLine":18}}}],"partialFingerprints":{"codehealthFindingId/v1":"4fc21aa8df2db82057f43bed113ae7fec4d5c35dbdfeaa11fd8407bbaa6b6720"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFDeveloperSettingsViewModel (LCOM4 5): WMFDeveloperSettingsViewModel\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Developer Settings/WMFDeveloperSettingsViewModel.swift"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"58bfff522f1c13317f0588e3a3e7008f7d44c02be5f863cbf03b9706237a474c"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFHistoryViewModel (LCOM4 5): WMFHistoryViewModel\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/History/WMFHistoryViewModel.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"69c5087ecc3869779a3afaaa4e9d86de7f03b785d87f4878f265ee8106106552"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFHomeDataController (LCOM4 5): WMFHomeDataController\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Home/WMFHomeDataController.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"00395acc4d60ea909d33286bc512477441b9ddda65847507b360c83f988cdb18"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSettingsDataController (LCOM4 5): WMFSettingsDataController\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Settings/WMFSettingsDataController.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"279147944f05db338a176194b5450993da74c165075268105761fb5865bc45c3"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFWatchlistDataController (LCOM4 5): WMFWatchlistDataController\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Watchlist/WMFWatchlistDataController.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"65eb8e417ce71439258193c11a9cb593bf1646a0a5e52479b75275d10bdf80a4"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFYearInReviewDataController (LCOM4 5): WMFYearInReviewDataController\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Year In Review/WMFYearInReviewDataController.swift"},"region":{"startLine":5}}}],"partialFingerprints":{"codehealthFindingId/v1":"36f5a9358e53016382bdc6ee6fa0921a0d60cad0088aad7c6c1e337497f5d34d"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: RemoteNotificationsController (LCOM4 5): RemoteNotificationsController\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Remote Notifications/RemoteNotificationsController.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"9125607cb1a56914424ccc0d1cc1ecd3e7a4157e664ca59970443d28811d0979"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: CollectionViewCell (LCOM4 5): CollectionViewCell\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/CollectionViewCell.swift"},"region":{"startLine":13}}}],"partialFingerprints":{"codehealthFindingId/v1":"ae149b5a60327db903bd810d0b0832a34a463e09898ad8841cead6fc55bb8757"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: DescriptionHelpViewController (LCOM4 5): DescriptionHelpViewController\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/DescriptionHelpViewController.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"cb975c72ef44de1bf1436fb7b16b95e692fa86a9f30eb8773cc35f2104fcc85a"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: EditSaveViewController (LCOM4 5): EditSaveViewController\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/EditSaveViewController.swift"},"region":{"startLine":50}}}],"partialFingerprints":{"codehealthFindingId/v1":"4d0ad7083d7f30b27735e97fb73b66ddb562dbcc7f513a49d2a13718c3f09451"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: NavigationStateController (LCOM4 5): NavigationStateController\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NavigationStateController.swift"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"6cc16bb098894148be98fd76f72ed755d3171b2236a3164b7d817f20eaf86c06"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: NotificationsCenterDetailViewController (LCOM4 5): NotificationsCenterDetailViewController\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NotificationsCenterDetailViewController.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"7a1f18dcd2dd6972ec8d4b4cacdc5a23dca164fd713f4a09ca2c3541dd58e330"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: NotificationsCenterViewController (LCOM4 5): NotificationsCenterViewController\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NotificationsCenterViewController.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"e60d0155bcaec62d8b6580b38d40c5322afbcad74511f1bc84c3774462162efe"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: NotificationsCenterViewModel (LCOM4 5): NotificationsCenterViewModel\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NotificationsCenterViewModel.swift"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"28cb606616397936ea52f81508fcd59a35181396b3c6c50eec650fe2f25c4485"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: PageHistoryViewController (LCOM4 5): PageHistoryViewController\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/PageHistoryViewController.swift"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"85c38175b5b23ec85633a4b2fdbd11ad81951d2bea6d95db42e97ce22af0e474"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: TalkPageCellViewModel (LCOM4 5): TalkPageCellViewModel\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TalkPageCellViewModel.swift"},"region":{"startLine":3}}}],"partialFingerprints":{"codehealthFindingId/v1":"248cdd70c5b6d81e30f9ddb3e07d18fc0ec690bd0ed6f39ef306c7ae1e9b37d8"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ThemeableTextView (LCOM4 5): ThemeableTextView\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ThemeableTextView.swift"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"cf30d075a9fcf405b272044d542d8cc408a142b94508baee16330feea746b3a5"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFWelcomeLanguageTableViewController (LCOM4 5): WMFWelcomeLanguageTableViewController\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFWelcomeLanguageTableViewController.swift"},"region":{"startLine":18}}}],"partialFingerprints":{"codehealthFindingId/v1":"04c19c6b5b1a68b783f9506602a6f666d016ed3cd3a0120948ec400432d8ba8d"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: UIScrollView (LCOM4 5): UIScrollView\u0027s methods fall into 5 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 5 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/UIScrollView\u002BLimits.swift"},"region":{"startLine":3}}}],"partialFingerprints":{"codehealthFindingId/v1":"dd31613b6cd95b46894b65b2c7d4cd919b9415e8a63cb1317351abf4c768c4a2"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFFindInPageViewModel (LCOM4 4): WMFFindInPageViewModel\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Shared/WMFFindInPageView.swift"},"region":{"startLine":25}}}],"partialFingerprints":{"codehealthFindingId/v1":"a65042dce05be9c743aa1a1cb54a564f16e2f710aaacaae6d1cf81e2f87b9db4"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: TimelineViewModel (LCOM4 4): TimelineViewModel\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/TimelineViewModel.swift"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"2890061700f5dfd65025d9af62307954073c40b1d8308819f0605dd0641b1cba"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSourceEditorFormatterBoldItalics (LCOM4 4): WMFSourceEditorFormatterBoldItalics\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorFormatterBoldItalics.swift"},"region":{"startLine":13}}}],"partialFingerprints":{"codehealthFindingId/v1":"878b873369075cdb4af6249332fcf6ac9d107d31014835e3ef00738e755b4dde"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSourceEditorFormatterComment (LCOM4 4): WMFSourceEditorFormatterComment\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorFormatterComment.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"4dc14f0714f5d666e6275110ff4ae19334b4011da14d9fa2cd6a1f64d066bc79"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSourceEditorFormatterReference (LCOM4 4): WMFSourceEditorFormatterReference\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorFormatterReference.swift"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"04789714d50574b6814354f119a07a3da721d333a87c71cb44ea9fc796d9aa05"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSourceEditorFormatterStrikethrough (LCOM4 4): WMFSourceEditorFormatterStrikethrough\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorFormatterStrikethrough.swift"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"8b5556665cf592f59ce9e88b0790b6d611813ebcc8c2f1f9edd411f0753786b8"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSourceEditorFormatterSubscript (LCOM4 4): WMFSourceEditorFormatterSubscript\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorFormatterSubscript.swift"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"f47b3838947c7dfd9d708c26787a0bdde0c604cf6d933d4539cb8b464c1d67e1"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSourceEditorFormatterSuperscript (LCOM4 4): WMFSourceEditorFormatterSuperscript\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorFormatterSuperscript.swift"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"6727aaa8ff4e0533dbf75c6ba869d51e8b8c1b163441ae3ad908e01fc50eb722"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSourceEditorFormatterTemplate (LCOM4 4): WMFSourceEditorFormatterTemplate\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorFormatterTemplate.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"30a5c86b16acdf09e7e8fa7df890d1842f9bbf0999336df6f14591e0a837a637"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSourceEditorFormatterUnderline (LCOM4 4): WMFSourceEditorFormatterUnderline\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Editors/Source Editor/WMFSourceEditorFormatterUnderline.swift"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"27efe4b717af3f7be8af094db68e462cf6ee697c39ccbb51f004954f724f5b61"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFWhichCameFirstResultsViewModel (LCOM4 4): WMFWhichCameFirstResultsViewModel\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Results/WMFWhichCameFirstResultsViewModel.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"dcc5f4cbf2279b8ab884bb86e090bb437efa5a30b8a23b50cba88748758d31f9"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFCoreDataStore (LCOM4 4): WMFCoreDataStore\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Store/WMFCoreDataStore.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"5a82b5a2cb7f59f2f4fc342e0903965bd0d87767cf89a2362e0d03c3b1598f5a"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFArticleTabsDataController (LCOM4 4): WMFArticleTabsDataController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"39d80cc201691b524c65d2cdbcb37d66cab2b010a8b536f1447f739e2544db45"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFDeveloperSettingsDataController (LCOM4 4): WMFDeveloperSettingsDataController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Developer Settings/WMFDeveloperSettingsDataController.swift"},"region":{"startLine":19}}}],"partialFingerprints":{"codehealthFindingId/v1":"83af9b578e120a9d0d9241b429bc70285ec76257c5e45b95cc00a1a4b4d43f7d"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFHistoryDataController (LCOM4 4): WMFHistoryDataController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/History /WMFHistoryDataController.swift"},"region":{"startLine":30}}}],"partialFingerprints":{"codehealthFindingId/v1":"eb68ce4e6f5a626515dcbb590c950aae6cb78db692c393c32a5d6601bab64f70"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFSavedArticlesDataController (LCOM4 4): WMFSavedArticlesDataController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Saved Articles/WMFSavedArticlesDataController.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"2a83c464539591b81f718239dac0082f3fb86f78a435c0206631c17012d9dc4e"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: Funnel (LCOM4 4): Funnel\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Instrument/Funnel.swift"},"region":{"startLine":3}}}],"partialFingerprints":{"codehealthFindingId/v1":"5168f792fde5d181afcea891b231c866b3b106909698cf59d988d99e850d3492"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: TestKitchenAdapter (LCOM4 4): TestKitchenAdapter\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/TestKitchenAdapter.swift"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"a304caa2a23b9cffa6a3b86a12d5dbbb503a96aa66c6123ad8a8df73e01013b1"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFCaptchaViewController (LCOM4 4): WMFCaptchaViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/WMFCaptchaViewController.swift"},"region":{"startLine":33}}}],"partialFingerprints":{"codehealthFindingId/v1":"30fc7ad2ca381ec35aa12beef30991babe60877005e5ffefefc0c09075321e3e"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WidgetController (LCOM4 4): WidgetController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Widget/WidgetController.swift"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"6af7c47061754e888e98f4c59d531a2911765803b039c660ea82b9ea74325f9e"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ArticleCacheDBWriter (LCOM4 4): ArticleCacheDBWriter\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleCacheDBWriter.swift"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"660825f87e8ac19234de2dc35a2775dadd0bb0f3fa29e061eaf1860996feb53d"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ArticleFullWidthImageCollectionViewCell (LCOM4 4): ArticleFullWidthImageCollectionViewCell\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleFullWidthImageCollectionViewCell.swift"},"region":{"startLine":3}}}],"partialFingerprints":{"codehealthFindingId/v1":"c415acbe7f43695f073d1ba5a68c2af352c2b85384ffa6c5e02f000ad1b27816"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: HelpViewController (LCOM4 4): HelpViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/HelpViewController.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"66259872a096e5190332c328aa96cd73099723e351bf5e452ba956d3a601f5d4"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: HintViewController (LCOM4 4): HintViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/HintViewController.swift"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"f855facb9ed3574505228773c1c18decab58ce30ad98764cfb18d65ef54eb92d"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: LibrariesUsedViewController (LCOM4 4): LibrariesUsedViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/LibrariesUsed.swift"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"1e5513c1c8a3e5188f3dc3e8a44abb510eeaf1702d8fe2c0dc1a1afcdacd34e0"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: PageIssuesTableViewController (LCOM4 4): PageIssuesTableViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/PageIssuesTableViewController.swift"},"region":{"startLine":5}}}],"partialFingerprints":{"codehealthFindingId/v1":"bcf0785c21dd782a7281d4aaac6608113dca7c6eb5b260a7b0ab5f061fd8eb22"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: ReadingThemesControlsViewController (LCOM4 4): ReadingThemesControlsViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ReadingThemesControlsViewController.swift"},"region":{"startLine":10}}}],"partialFingerprints":{"codehealthFindingId/v1":"506cfdbaf1e86106f7a1fe07e1f195460389ae03b66d98690f7ca7faad73914d"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: SavedArticlesCollectionViewCell (LCOM4 4): SavedArticlesCollectionViewCell\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/SavedArticlesCollectionViewCell.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"70d415b0695da9620beefcc0269e448dcc727bed20a220c00a138416697bffc2"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: SubSettingsViewController (LCOM4 4): SubSettingsViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/SubSettingsViewController.swift"},"region":{"startLine":3}}}],"partialFingerprints":{"codehealthFindingId/v1":"79dd774c5bdeb2240fccc644c170eb063354fdcc3bdc3d5142adf2a0b539c5b0"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: TempAccountExpiryViewController (LCOM4 4): TempAccountExpiryViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/TempAccountExpiryViewController.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"991ae1bead5a294f91da230cf5044bfa72525f2d7bb6fe4a8d2f9a986043873b"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFScrollViewController (LCOM4 4): WMFScrollViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFScrollViewController.swift"},"region":{"startLine":3}}}],"partialFingerprints":{"codehealthFindingId/v1":"ec49bc0512f57497459ad064b948c5708f93c798d7d6148d76396f161311dd93"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: WMFWelcomeContainerViewController (LCOM4 4): WMFWelcomeContainerViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFWelcomeContainerViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"9757cfad7d5c167b0bf0563aa2b925e66f0861e244578ee1b0c6528dd5671bb5"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: InsertMediaImagePositionSettingsViewController (LCOM4 4): InsertMediaImagePositionSettingsViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/Advanced Settings/InsertMediaImagePositionSettingsViewController.swift"},"region":{"startLine":3}}}],"partialFingerprints":{"codehealthFindingId/v1":"62af28d05e39f68f5faeeff35506076968da07bd6348ab4fce4825865d0c4c4c"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: InsertMediaImageTypeSettingsViewController (LCOM4 4): InsertMediaImageTypeSettingsViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/Advanced Settings/InsertMediaImageTypeSettingsViewController.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"7c2efef8eee643e60e99a848644c6880cfe8564a6c2d536be9ff3bc33ef79be4"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: TempAccountsSettingsViewController (LCOM4 4): TempAccountsSettingsViewController\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/Temp Accounts/TempAccountsSettingsViewController.swift"},"region":{"startLine":17}}}],"partialFingerprints":{"codehealthFindingId/v1":"6a54a5d1d7976d8a766d1a53b73ce484fdf94bf36e9cca7ebd116ab3f255f908"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: URL (LCOM4 4): URL\u0027s methods fall into 4 groups that share no field and call none of each other, against a bar of more than 3 for this run (LCOM4, configurable \u2014 your repository\u0027s bar is the one quoted here). Each group is a set of methods reachable from one another through shared fields or direct calls, so 4 groups means the type has that many internally-connected clusters with nothing tying them together. Types whose shape makes a high count expected \u2014 and which would otherwise dominate this list \u2014 are excluded before this row is raised, so this is a genuine split candidate rather than a metric reading. It is still a shape, not a defect: confirm the groups match responsibilities you can name before splitting."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Widgets/Widgets/URL\u002BWidgetSource.swift"},"region":{"startLine":18}}}],"partialFingerprints":{"codehealthFindingId/v1":"f00d782917b23aed428a17b780cae74176606bd71eb1baa0767344fd20ef5fa7"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/Config/SourceConfig.swift: 0.0% line coverage (0/6)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Config/SourceConfig.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"13df6ce6bcbc7b1082acd7a2e22c049634bc3258a11b7d0ea622db61dcd93665"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/Context/AgentData.swift: 0.0% line coverage (0/12)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Context/AgentData.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"25a144294d55a9c9627c0224ce80f6f57a8280bba44961d38d62f3f3d9a94c0a"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/Context/ClientData.swift: 0.0% line coverage (0/5)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Context/ClientData.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"ca8ac97081a57466e9a4e8af1b72bf80b0a08c3cc3a67137a1e647ed17cc3744"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/Context/ExperimentData.swift: 0.0% line coverage (0/5)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Context/ExperimentData.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"afa89ea4de977af143cd1bbb1ae88b902f4449aecf58e442d7df434dbd7bfd5c"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/Context/InteractionData.swift: 0.0% line coverage (0/11)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Context/InteractionData.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"544287249b336d47d2bf373b31b41c6b4a77fa7179153346347bbe7582223e0a"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/Context/MediawikiData.swift: 0.0% line coverage (0/3)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Context/MediawikiData.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"9a5654c542ebbe90aa7b9d4f3a0439dbabcb0bac1c777f897c7d97e8ce75ba02"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/Context/PageData.swift: 0.0% line coverage (0/9)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Context/PageData.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"1bb201ccc6620410519e63c351dc06617ef40abfe376abf4e7d24fac202998f1"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/Context/PerformerData.swift: 0.0% line coverage (0/28)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Context/PerformerData.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"830b94b625505506ee5622871833e91fb20825e850bfbd6c656ebbe6d8ba0e77"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/ContextController.swift: 0.0% line coverage (0/51)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/ContextController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"c1c2e2cf1ca3791bcfd285cc4f76a39e91c994ce7a64b82eac33193c5cb5b53d"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/Error\u002BExtension.swift: 0.0% line coverage (0/14)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Error\u002BExtension.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"adec7e46a260fdff2c272fc72cab6764c2825f14a9c7376807bf94fe93bde34c"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/Event/Event.swift: 0.0% line coverage (0/37)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Event/Event.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"31f1f7448513ac547dbaba02e01558f84e4aa9ca0a1fecd8bf57cb9c0875af0f"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/Instrument/Funnel.swift: 0.0% line coverage (0/34)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Instrument/Funnel.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"2fa448d6c84076a9942c060f4bcc071bcd213691e5bca572c1538bf844526a27"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/Instrument/InstrumentImpl.swift: 0.0% line coverage (0/54)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/Instrument/InstrumentImpl.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"59c1203bea540e23fd2b11510c7c8076d5a5d08cf22d6f4403815ccab1509fec"}},{"ruleId":"D8","level":"warning","message":{"text":"Low coverage: WMFTestKitchen/Sources/WMFTestKitchen/TestKitchenClient.swift: 0.0% line coverage (0/42)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFTestKitchen/Sources/WMFTestKitchen/TestKitchenClient.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"fd1d5b81f03aee13cf59de5ff6b038768f8586fb4c20098e917c97f0f24d37c4"}},{"ruleId":"D10","level":"warning","message":{"text":"Skipped test: testArticleNonLeadImageCanBeTapped: Skipped \u2014 throws XCTSkip"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":108}}}],"partialFingerprints":{"codehealthFindingId/v1":"7c33df013738c240b8d7a7aebfe828e5ca1af6884d3380dcfaf2c3521b3c7e0b"}},{"ruleId":"D10","level":"warning","message":{"text":"Skipped test: testArticleLinkLongPressShowsPreviewAndMenuItems: Skipped \u2014 throws XCTSkip"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":120}}}],"partialFingerprints":{"codehealthFindingId/v1":"b2f1c73983a907157edadc7c9590ac359d8c5411147c2e06f79e486424f76275"}},{"ruleId":"D10","level":"warning","message":{"text":"Skipped test: testQuickFactsArticleLinkLongPressShowsPreviewAndMenuItems: Skipped \u2014 throws XCTSkip"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":131}}}],"partialFingerprints":{"codehealthFindingId/v1":"c610a2ae3dcad4f737802ab8a23702ae2564aa1261614a80dab1b1b56087465d"}},{"ruleId":"D10","level":"warning","message":{"text":"Skipped test: testArticleTableItemsCanBeTapped: Skipped \u2014 throws XCTSkip"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":154}}}],"partialFingerprints":{"codehealthFindingId/v1":"cba4d4be845141ec74f55e3d507705929bebb7af0575f31d2dc9f91422716b5e"}},{"ruleId":"D10","level":"warning","message":{"text":"Skipped test: testBohemiaLeadImageOpensImageGalleryAndCanShare: Skipped \u2014 throws XCTSkip"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleImageGalleryUITests.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"de16da257a9694cc8510e0f2632edc12d4eddba4045dbd7b54bd0c0066eb9518"}},{"ruleId":"D10","level":"warning","message":{"text":"Skipped test: testHostingItemPrefersTheVerticalBarOnIPhoneDuo: Skipped \u2014 throws XCTSkip"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Tests/WMFComponentsTests/WMFBarButtonHostingViewTests.swift"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"50b87148c1efde657518d542dfac7af457f5486cec2e248af1a61331b2980b30"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testFirstLaunchShowsOnboardingSmoke: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/AppOnboardingUITests.swift"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"f08dd7a437d03b154284439c1bf87fce010fe09479e521087949835589b6dde9"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testOnboardingScreenshots: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/AppOnboardingUITests.swift"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"00892a295939dde78cf142d532504bf735f24e5f845f13c40a4123ffee9f046e"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testLearnMoreLinksPresentDestinations: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/AppOnboardingUITests.swift"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"ec7255248cb4b5d46aee552fbda14d04dd1449f6d5bbac2116d48bd5d2577a40"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testAdditionalLanguageCanBeAddedDuringOnboarding: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/AppOnboardingUITests.swift"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"9a05f8933d8eb323b95c080400ce83236edca5c386e342a083e9bb363c07ec25"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testLaunchLocaleSeedsPreferredWikipediaLanguage: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/AppOnboardingUITests.swift"},"region":{"startLine":62}}}],"partialFingerprints":{"codehealthFindingId/v1":"5eada1c2de86cfd4e85504295cce202ef205c3b41d69906d7e5442ba0204028a"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testWelcomeScreensCanBeAdvancedByTappingNext: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/AppOnboardingUITests.swift"},"region":{"startLine":75}}}],"partialFingerprints":{"codehealthFindingId/v1":"2cba0b5fa26a943074a2f63ea24e2c42fd275cf0ecd1a027b0619c81ff74beba"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testWelcomeScreensCanBeAdvancedBySwiping: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/AppOnboardingUITests.swift"},"region":{"startLine":87}}}],"partialFingerprints":{"codehealthFindingId/v1":"6ebfdf2a564046aaf276f798f66f0b46bfc6961911cb366c3acb853757bc8b2f"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testOnboardingCanBeSkipped: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/AppOnboardingUITests.swift"},"region":{"startLine":96}}}],"partialFingerprints":{"codehealthFindingId/v1":"d8459912cbff4a0ae61b28a6ace0e848a30aa0785b7ed5bac1fb4e9b63b0abdb"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleBackButtonReturnsToExplore: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"e85c19c35e7d51744bdc3eec2d963c37b1ff92d88d258c6bf7a1d4fafd573f36"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleHomeButtonReturnsToExplore: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"fd54a9a7ced14f578d60095255331ce09a090751f6429b2c358ca3530162f563"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleSearchButtonOpensSearch: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"611ae0f777c30a082d0b4a02ef4c053c5a0dc93aecc80c5d33cf7cce474c888d"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleTableOfContentsButtonOpensContents: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":19}}}],"partialFingerprints":{"codehealthFindingId/v1":"46418e99e1090f8685ad5d44a4a04907cd55a1761fa8e4a078fe50a199fd2672"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleLanguageControlSwitchesArticleLanguage: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"3163af496217c13a22218e8ee028dcb481d8538aad627268e936fb02b9184595"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleSaveControlTogglesSavedState: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":31}}}],"partialFingerprints":{"codehealthFindingId/v1":"cd5b7f7868fa6c501f67ffe670d71a9b28cf5f2a763a49adedec61c10e197958"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleFindInArticleSearchesAndCloses: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"2597246cba6573aab1f0f3ca6baebbb10d7e42acf045498a3f0da91f794175ac"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleThemeControlAdjustsReadingTheme: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":42}}}],"partialFingerprints":{"codehealthFindingId/v1":"3426f6aceb4a0e48ee49a3573a4eef2f0554c71f1ce053627ffb0697ea1f94e6"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleTableOfContentsDismissesWhenTappingOutside: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"171b213439db2c0131d66c40245cc16300df52d0783086e3e9c1038319f192f3"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleTableOfContentsSectionSelectionWorks: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":55}}}],"partialFingerprints":{"codehealthFindingId/v1":"d36e442d6a1289ccfc8901a05b1a57cc2e0ed33e0817e832360c1ecbb983c323"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleTableOfContentsWorksAfterRotation: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":70}}}],"partialFingerprints":{"codehealthFindingId/v1":"cec07af35d58f2c8458244db752e06bdfe97ea6f237141c21f70aa25f65b83af"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleOverflowMenuItemsAreAvailable: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":75}}}],"partialFingerprints":{"codehealthFindingId/v1":"191683b08992f0ff6f7487b1f75bb0c7b00ec2d062d796ab72baf55d8769d45e"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleOverflowWatchCanBeTapped: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":82}}}],"partialFingerprints":{"codehealthFindingId/v1":"b4f6d0c3f2f65d34ba128e2470b7ddeefcee64315f6e06b5517484ca33342301"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleOverflowTalkPageCanBeTapped: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":87}}}],"partialFingerprints":{"codehealthFindingId/v1":"5bc6cde8639aebb2328d9c4e1efb4e77d15194b167b63782f7cc7bccaa8860ee"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleOverflowEditSourceCanBeTapped: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":92}}}],"partialFingerprints":{"codehealthFindingId/v1":"b28dc36d88a94368dbf35f86ecd46798aeccd175183902a9ee13fcbc6f9bd427"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleOverflowBackReturnsToPreviousArticle: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":97}}}],"partialFingerprints":{"codehealthFindingId/v1":"60ae4c5ed47310d93ddb1b1c6af9d0c85c2f8e4a66b33ab468be509c230cf594"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleOverflowRevisionHistoryCanBeTapped: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"c2d9cb896405d0d76f6523b8ef9891692034543e41a1b274094f219ad1f76628"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testProtectedArticleEditIconCanBeTapped: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":142}}}],"partialFingerprints":{"codehealthFindingId/v1":"1bfd36d216c6674740bc17ce29ef75119f9feb306518f340dbfe93f2e7997409"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testUnprotectedArticleEditIconCanBeTapped: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":148}}}],"partialFingerprints":{"codehealthFindingId/v1":"d053403e4bbd9f331f883a1e49cf6ee4b46b992800be646edb76d74a0f3d62a2"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleFooterAndLicenseLinksCanBeTapped: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":165}}}],"partialFingerprints":{"codehealthFindingId/v1":"2a9a94ea187ae1fa8ec0e9c911bfdb9c6c5a8ed3bda8c2eddef6cfc5e5f3598b"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testArticleWorksAfterRotation: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ArticleControlsUITests.swift"},"region":{"startLine":177}}}],"partialFingerprints":{"codehealthFindingId/v1":"42b7ddc4f77cd6b2e758c263dfa4ddb5ff46fcc8fd8514df5432497f3cb91560"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testExplore: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ExploreUITests.swift"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"180dee2bb6e7e6fc2c8e6f9b0e48cebb64d8b3667641fd5c5858568271ab15c2"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testExploreTopTabsButtonOpensArticleTabs: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ExploreUITests.swift"},"region":{"startLine":18}}}],"partialFingerprints":{"codehealthFindingId/v1":"a61b240773b8354e57d131933b028d2ecc78402b8ecdaab2892da158ef94269a"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testExploreTopProfileButtonOpensProfile: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ExploreUITests.swift"},"region":{"startLine":25}}}],"partialFingerprints":{"codehealthFindingId/v1":"12efba1c3fe98288db2af8633850431e77ca715af6c4daf0c5e2b1c30039d5d9"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testExploreBottomTabsCanBeTapped: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ExploreUITests.swift"},"region":{"startLine":32}}}],"partialFingerprints":{"codehealthFindingId/v1":"ac2403ccba9bde0199e1533e3ab10ad5142b70ceff0a1681ec95ae29b3ab54c8"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testExploreBottomTabsExposeAccessibilityIdentifiers: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ExploreUITests.swift"},"region":{"startLine":43}}}],"partialFingerprints":{"codehealthFindingId/v1":"b5c05cd656cd937e1c5f82707907cff75a793aa9f842a6ea3af86ea3eb0d4f8b"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testExploreSearchShowsResult: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ExploreUITests.swift"},"region":{"startLine":50}}}],"partialFingerprints":{"codehealthFindingId/v1":"7a513a197e0bc751883e95c4a8ec666b9e960ad29a2ce1303d1dd3b73cfeae4e"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testExploreSearchResultStaysVisibleAfterRotation: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ExploreUITests.swift"},"region":{"startLine":62}}}],"partialFingerprints":{"codehealthFindingId/v1":"575d18b928e68058e2de494da5abce33739525044b167e5b6a24832be1a9b56f"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testExploreSearchResultOpensArticle: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ExploreUITests.swift"},"region":{"startLine":79}}}],"partialFingerprints":{"codehealthFindingId/v1":"0e80cd1bc6ba5531753d04cb11ff107d080cb3a9981ab57c8f82f2ff5828d269"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testExploreRecentSearchesCanBeCleared: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/ExploreUITests.swift"},"region":{"startLine":94}}}],"partialFingerprints":{"codehealthFindingId/v1":"377f15c3e6a93509213b4beb74b3de9abd2e0457e76e9b30e1e6e55922c1f200"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testFirstLaunchShowsOnboardingSmoke: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/NewAppOnboardingUITests.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"396b9b3d40a90ca92b2c608ee119748b56666a4ec7b5b73398b8ba61c472a5f8"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testLegacyOnboardingShownWhenHomeTabDisabled: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/NewAppOnboardingUITests.swift"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"8bcb616ee6951b897f7432ec26e2ac9894dc11a269f9a7b99e0e77c3335d2c8a"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testOnboardingScreenshots: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/NewAppOnboardingUITests.swift"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"ea8c4276b1d770af4c586fd55d87fcb22c26b2ce1637cfcde73e5617acfd8c20"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testAdvanceThroughAllStepsCompletesOnboarding: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/NewAppOnboardingUITests.swift"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"282b3fd1c7e97c3780f7d1cc7fee909d22a2d89c0d6c151566c21988696745d7"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testSkipFromPersonalizationCompletesOnboarding: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/NewAppOnboardingUITests.swift"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"eed01e0d41723bd93a7d765e38c7d56baef06edaac74b417dd67a498e1f3178e"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testLearnMoreLinksPresentDestinations: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/NewAppOnboardingUITests.swift"},"region":{"startLine":72}}}],"partialFingerprints":{"codehealthFindingId/v1":"14631b6e19e0e59d2c8aa91eac11ef44e3c01f626999094e0cedd3dd21b3aedf"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testAdditionalLanguageCanBeAddedDuringOnboarding: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/NewAppOnboardingUITests.swift"},"region":{"startLine":81}}}],"partialFingerprints":{"codehealthFindingId/v1":"c60253c16ede04a3b4d650ddb29f9aff3af09b6efd1a7039439506d53f43aa9d"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testLaunchLocaleSeedsPreferredWikipediaLanguage: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/NewAppOnboardingUITests.swift"},"region":{"startLine":99}}}],"partialFingerprints":{"codehealthFindingId/v1":"21e14941d75b4aac11b8a77eb14ac7be9cbe1829ad3166460bee925e6efeda45"}},{"ruleId":"D10","level":"note","message":{"text":"No direct assertions: testInterestsSearchAddsArticle: No conventional assertion call was detected, and 47 of 47 tests in \u0060WikipediaUITests\u0060 read the same way \u2014 so this is treated as that project\u0027s convention rather than a broken test, and it does not drag the score. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a project of runnable samples compiled as tests, where a run that does not throw is the only check. If it is the latter, these methods genuinely verify nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/NewAppOnboardingUITests.swift"},"region":{"startLine":113}}}],"partialFingerprints":{"codehealthFindingId/v1":"3ee5e663ef50ab93d0337a7bbac947833d4937fc5c148db86c62af43327ae53b"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: successDoesNotCallHTTPErrorLogger: This method\u0027s body runs code, and no assertion call was recognised in it. Recognised by name: Assert*, *Should*/ShouldBe*, Verify, Expect, Throws, Record, Received/DidNotReceive, MustHaveHappened/MustNotHaveHappened, EnsureSuccessStatusCode and *AndEnsure* \u2014 so verification routed through a helper of your own naming, through a base-class or callback object whose members hold the assertions, or through a harness that fails by throwing under some other name, is not visible to this check and is not counted here. Read it as \u0027no assertion this check knows how to see\u0027, and if that is right, add one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Tests/WMFDataTests/WMFBasicServiceHTTPErrorLoggerTests.swift"},"region":{"startLine":50}}}],"partialFingerprints":{"codehealthFindingId/v1":"d3ee65453f4a26bc7be0e6c67f530f3df9cf5fce506b0951776784c2e8c0b7cf"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: donateSubmitPayment: This method\u0027s body runs code, and no assertion call was recognised in it. Recognised by name: Assert*, *Should*/ShouldBe*, Verify, Expect, Throws, Record, Received/DidNotReceive, MustHaveHappened/MustNotHaveHappened, EnsureSuccessStatusCode and *AndEnsure* \u2014 so verification routed through a helper of your own naming, through a base-class or callback object whose members hold the assertions, or through a harness that fails by throwing under some other name, is not visible to this check and is not counted here. Read it as \u0027no assertion this check knows how to see\u0027, and if that is right, add one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Tests/WMFDataTests/WMFDonateDataControllerTests.swift"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"f8b1cb2653184b7b2f856f4ab293c28942c225e00988f6c7988c75cc63b2863f"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: testFetchFeedSucceeds: This method\u0027s body runs code, and no assertion call was recognised in it. Recognised by name: Assert*, *Should*/ShouldBe*, Verify, Expect, Throws, Record, Received/DidNotReceive, MustHaveHappened/MustNotHaveHappened, EnsureSuccessStatusCode and *AndEnsure* \u2014 so verification routed through a helper of your own naming, through a base-class or callback object whose members hold the assertions, or through a harness that fails by throwing under some other name, is not visible to this check and is not counted here. Read it as \u0027no assertion this check knows how to see\u0027, and if that is right, add one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Tests/WMFDataTests/WMFFeedDataControllerTests.swift"},"region":{"startLine":25}}}],"partialFingerprints":{"codehealthFindingId/v1":"9f9afa6f805e458ae63a79431478b28a4d14a4887378dc6bbc8b04f50d612360"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: testFetchCommunitySucceeds: This method\u0027s body runs code, and no assertion call was recognised in it. Recognised by name: Assert*, *Should*/ShouldBe*, Verify, Expect, Throws, Record, Received/DidNotReceive, MustHaveHappened/MustNotHaveHappened, EnsureSuccessStatusCode and *AndEnsure* \u2014 so verification routed through a helper of your own naming, through a base-class or callback object whose members hold the assertions, or through a harness that fails by throwing under some other name, is not visible to this check and is not counted here. Read it as \u0027no assertion this check knows how to see\u0027, and if that is right, add one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Tests/WMFDataTests/WMFHomeDataControllerTests.swift"},"region":{"startLine":348}}}],"partialFingerprints":{"codehealthFindingId/v1":"4058f13db848e6f58b83ba826f37c9ceba0847f0bcc85d0dc898837524929b4d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: fetchImageInfoReturnsUnexpectedResponseWhenNoPages: This method\u0027s body runs code, and no assertion call was recognised in it. Recognised by name: Assert*, *Should*/ShouldBe*, Verify, Expect, Throws, Record, Received/DidNotReceive, MustHaveHappened/MustNotHaveHappened, EnsureSuccessStatusCode and *AndEnsure* \u2014 so verification routed through a helper of your own naming, through a base-class or callback object whose members hold the assertions, or through a harness that fails by throwing under some other name, is not visible to this check and is not counted here. Read it as \u0027no assertion this check knows how to see\u0027, and if that is right, add one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Tests/WMFDataTests/WMFImageDataControllerTests.swift"},"region":{"startLine":161}}}],"partialFingerprints":{"codehealthFindingId/v1":"0a25b2564b464307fe08b5c99c14140d1c6916d8205ca59ce1813c24f4a975d1"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: fetchImageInfoFailsWhenMediaWikiServiceUnavailable: This method\u0027s body runs code, and no assertion call was recognised in it. Recognised by name: Assert*, *Should*/ShouldBe*, Verify, Expect, Throws, Record, Received/DidNotReceive, MustHaveHappened/MustNotHaveHappened, EnsureSuccessStatusCode and *AndEnsure* \u2014 so verification routed through a helper of your own naming, through a base-class or callback object whose members hold the assertions, or through a harness that fails by throwing under some other name, is not visible to this check and is not counted here. Read it as \u0027no assertion this check knows how to see\u0027, and if that is right, add one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Tests/WMFDataTests/WMFImageDataControllerTests.swift"},"region":{"startLine":177}}}],"partialFingerprints":{"codehealthFindingId/v1":"65fced804040b3bce14c6c4fff884a5e65df57fcdb3b6784a74e5be5f810f479"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: fetchThrowsUnexpectedResponseWhenDataIsNil: This method\u0027s body runs code, and no assertion call was recognised in it. Recognised by name: Assert*, *Should*/ShouldBe*, Verify, Expect, Throws, Record, Received/DidNotReceive, MustHaveHappened/MustNotHaveHappened, EnsureSuccessStatusCode and *AndEnsure* \u2014 so verification routed through a helper of your own naming, through a base-class or callback object whose members hold the assertions, or through a harness that fails by throwing under some other name, is not visible to this check and is not counted here. Read it as \u0027no assertion this check knows how to see\u0027, and if that is right, add one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Tests/WMFDataTests/WMFUserImpactDataControllerTests.swift"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"f6f8915d03319d0d5bd7efa72670864368a5a2dee863864c359d57fe757bd412"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: fetchWrapsServiceFailureAsServiceError: This method\u0027s body runs code, and no assertion call was recognised in it. Recognised by name: Assert*, *Should*/ShouldBe*, Verify, Expect, Throws, Record, Received/DidNotReceive, MustHaveHappened/MustNotHaveHappened, EnsureSuccessStatusCode and *AndEnsure* \u2014 so verification routed through a helper of your own naming, through a base-class or callback object whose members hold the assertions, or through a harness that fails by throwing under some other name, is not visible to this check and is not counted here. Read it as \u0027no assertion this check knows how to see\u0027, and if that is right, add one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Tests/WMFDataTests/WMFUserImpactDataControllerTests.swift"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"857ef1b44bcc705e9cd2f015c53d235e202015f31320a82745c79391af8caba1"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: postWatchArticleExpiryNever: This method\u0027s body runs code, and no assertion call was recognised in it. Recognised by name: Assert*, *Should*/ShouldBe*, Verify, Expect, Throws, Record, Received/DidNotReceive, MustHaveHappened/MustNotHaveHappened, EnsureSuccessStatusCode and *AndEnsure* \u2014 so verification routed through a helper of your own naming, through a base-class or callback object whose members hold the assertions, or through a harness that fails by throwing under some other name, is not visible to this check and is not counted here. Read it as \u0027no assertion this check knows how to see\u0027, and if that is right, add one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Tests/WMFDataTests/WMFWatchlistDataControllerTests.swift"},"region":{"startLine":212}}}],"partialFingerprints":{"codehealthFindingId/v1":"aef9df0569de299efd54c6a78c4470c4445637f9c20c6a25c3a1c0f1c23d087a"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: postWatchArticleExpiryDate: This method\u0027s body runs code, and no assertion call was recognised in it. Recognised by name: Assert*, *Should*/ShouldBe*, Verify, Expect, Throws, Record, Received/DidNotReceive, MustHaveHappened/MustNotHaveHappened, EnsureSuccessStatusCode and *AndEnsure* \u2014 so verification routed through a helper of your own naming, through a base-class or callback object whose members hold the assertions, or through a harness that fails by throwing under some other name, is not visible to this check and is not counted here. Read it as \u0027no assertion this check knows how to see\u0027, and if that is right, add one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Tests/WMFDataTests/WMFWatchlistDataControllerTests.swift"},"region":{"startLine":221}}}],"partialFingerprints":{"codehealthFindingId/v1":"a203b7c18e26a994aa7f8f98249bc7392061e237e71f47b7ddce1b5e98f0a6e3"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: postUnwatchArticle: This method\u0027s body runs code, and no assertion call was recognised in it. Recognised by name: Assert*, *Should*/ShouldBe*, Verify, Expect, Throws, Record, Received/DidNotReceive, MustHaveHappened/MustNotHaveHappened, EnsureSuccessStatusCode and *AndEnsure* \u2014 so verification routed through a helper of your own naming, through a base-class or callback object whose members hold the assertions, or through a harness that fails by throwing under some other name, is not visible to this check and is not counted here. Read it as \u0027no assertion this check knows how to see\u0027, and if that is right, add one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Tests/WMFDataTests/WMFWatchlistDataControllerTests.swift"},"region":{"startLine":230}}}],"partialFingerprints":{"codehealthFindingId/v1":"16105c6b0a53e3016fb6ba2347a38ebf7813d8595b9b2b2682f681da69ea51ab"}},{"ruleId":"D10","level":"note","message":{"text":"Test project verifies nothing: WikipediaUITests: No conventional assertion call was detected in 47 of 47 tests in \u0060WikipediaUITests\u0060 \u2014 the project as a whole, not one method. Two things look like this: verification that happens indirectly (an approval/verifier harness or BDD step methods), or a suite that genuinely checks nothing. If it is the latter, this project passes unconditionally and cannot fail."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WikipediaUITests/AppOnboardingUITests.swift"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"4d73ad4b1d9a0cc15f977bfb58a7da06883270c084f71ab251f74d6a7587c704"}},{"ruleId":"D13","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":"5f5aa4f08bd8d16a4932ace57c746f89479e95be3579a5a3c7848d4eb15d4a07"},"taxa":[{"id":"CWE-259","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-798","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D13","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":"a4ce2f80d33a4181d53dabc8edcbee477db415fb5bb665891da0006d484c0488"},"taxa":[{"id":"CWE-259","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-798","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: Wikipedia/Code/DonateCoordinator.swift: Wikipedia/Code/DonateCoordinator.swift changed 23 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 66 in DonateCoordinator.presentActionSheet at line 226. 1 of those changes was a fix/bug commit, and the other 22 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- Wikipedia/Code/DonateCoordinator.swift\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":"Wikipedia/Code/DonateCoordinator.swift"},"region":{"startLine":226}}}],"partialFingerprints":{"codehealthFindingId/v1":"491996ec39db1c93de58ee94511cdff93c242d8bdfede2e1c9e31c6ec8992698"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: WMFComponents/Sources/WMFComponents/Style/WMFIcon.swift: WMFComponents/Sources/WMFComponents/Style/WMFIcon.swift changed 10 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 137 in WMFSFSymbolIcon.\u0060for\u0060 at line 203. 2 of those changes were fix/bug commits, and the other 8 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- WMFComponents/Sources/WMFComponents/Style/WMFIcon.swift\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":"WMFComponents/Sources/WMFComponents/Style/WMFIcon.swift"},"region":{"startLine":203}}}],"partialFingerprints":{"codehealthFindingId/v1":"11903d379842d77d0ff6a109ab2f9d1c9617311d57f090f179e21144c6c70e38"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: Wikipedia/Code/ArticleViewController.swift: Wikipedia/Code/ArticleViewController.swift changed 27 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 19 in ArticleViewController.showFundraisingCampaignAnnouncementIfNeeded at line 14. 3 of those changes were fix/bug commits, and the other 24 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- Wikipedia/Code/ArticleViewController.swift\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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"57393064a3d4fa11663be5ad80c11d497738c4bad92e664c0ca95d7c7df0d7bc"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: Wikipedia/Code/HomeCoordinator.swift: Wikipedia/Code/HomeCoordinator.swift changed 19 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 26 in HomeCoordinator.makeHomeViewController at line 53. 3 of those changes were fix/bug commits, and the other 16 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- Wikipedia/Code/HomeCoordinator.swift\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":"Wikipedia/Code/HomeCoordinator.swift"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"93c83abbd2e01697cfcce8406f95cb1535056dbea130f48a3a5fc115a21b915c"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: Wikipedia/Code/AppOnboardingCoordinator.swift: Wikipedia/Code/AppOnboardingCoordinator.swift changed 12 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 28 in AppOnboardingCoordinator.start at line 33. 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- Wikipedia/Code/AppOnboardingCoordinator.swift\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":"Wikipedia/Code/AppOnboardingCoordinator.swift"},"region":{"startLine":33}}}],"partialFingerprints":{"codehealthFindingId/v1":"d35a879f2b966481f54cf12a122bc45e2e07b005607c772cf4b3def2940dd342"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: Wikipedia/Code/SettingsCoordinator.swift: Wikipedia/Code/SettingsCoordinator.swift changed 13 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 23 in SettingsCoordinator.handleSettingsAction at line 139. 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- Wikipedia/Code/SettingsCoordinator.swift\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":"Wikipedia/Code/SettingsCoordinator.swift"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"94af91c35770480e76913691270d0f5e8177492a5771bab8a5042d078a921905"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: WMF Framework/Widget/WidgetController.swift: WMF Framework/Widget/WidgetController.swift changed 12 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 16 in WidgetController.fetchTopReadContent at line 370. 2 of those changes were fix/bug commits, and the other 10 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- WMF Framework/Widget/WidgetController.swift\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":"WMF Framework/Widget/WidgetController.swift"},"region":{"startLine":370}}}],"partialFingerprints":{"codehealthFindingId/v1":"2b74cce0b2866a155464706c563a51e45a5bfe5b98949dfc7eac201519a3def4"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift: WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift changed 10 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 19 in WMFActivityTabView.loggedInList at line 80. 2 of those changes were fix/bug commits, and the other 8 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift\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":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift"},"region":{"startLine":80}}}],"partialFingerprints":{"codehealthFindingId/v1":"b2d7c01da393e7cb1c748a25e71418db985c9938ef46d8173e93bcc4a87773e4"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: WMFData/Sources/WMFData/Data Controllers/Experiments/WMFExperimentsDataController.swift: WMFData/Sources/WMFData/Data Controllers/Experiments/WMFExperimentsDataController.swift changed 6 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 18 in WMFExperimentsDataController.determineBucketForExperiment at line 117. 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- WMFData/Sources/WMFData/Data Controllers/Experiments/WMFExperimentsDataController.swift\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":"WMFData/Sources/WMFData/Data Controllers/Experiments/WMFExperimentsDataController.swift"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"d0146feaafca2e4795f7513786f664e4e316e1844ec2a1bdb5d95c7d0ab89707"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: WMFData/Sources/WMFData/Service/WMFBasicService.swift: WMFData/Sources/WMFData/Service/WMFBasicService.swift changed 4 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 17 in WMFBasicService.performPOST at line 59. 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- WMFData/Sources/WMFData/Service/WMFBasicService.swift\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":"WMFData/Sources/WMFData/Service/WMFBasicService.swift"},"region":{"startLine":59}}}],"partialFingerprints":{"codehealthFindingId/v1":"afdf63fe4a152b1e3f85430344544303e4977171012e15fb6c21f11bbd459826"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: WMFComponents/Sources/WMFComponents/Components/Home/WMFCommunityFeedView.swift: WMFComponents/Sources/WMFComponents/Components/Home/WMFCommunityFeedView.swift changed 4 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 17 in WMFCommunityFeedView.feedList at line 39. 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- WMFComponents/Sources/WMFComponents/Components/Home/WMFCommunityFeedView.swift\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":"WMFComponents/Sources/WMFComponents/Components/Home/WMFCommunityFeedView.swift"},"region":{"startLine":39}}}],"partialFingerprints":{"codehealthFindingId/v1":"862838f0d468f221bc9542a01eec1a92ed730123b5dd2c86c5588018a9069d1d"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: Wikipedia/Code/ArticlePeekPreviewViewController.swift: Wikipedia/Code/ArticlePeekPreviewViewController.swift changed 2 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 23 in ArticlePeekPreviewViewController.contextMenuItems at line 115. 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- Wikipedia/Code/ArticlePeekPreviewViewController.swift\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":"Wikipedia/Code/ArticlePeekPreviewViewController.swift"},"region":{"startLine":115}}}],"partialFingerprints":{"codehealthFindingId/v1":"5ed343614d791c9802b640d743a980b63c77403ad7e44b55683df5eacf53e148"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleDataController.swift: WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleDataController.swift changed 2 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 17 in WMFArticleDataController.fetchArticleInfo at line 102. 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleDataController.swift\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":"WMFData/Sources/WMFData/Data Controllers/Shared/WMFArticleDataController.swift"},"region":{"startLine":102}}}],"partialFingerprints":{"codehealthFindingId/v1":"01388ada2a99f76b791114ca325551c0c60d37f04c5a1778ced371032487c1e5"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: WMFComponents/Sources/WMFComponents/Components/Shared/Survey/WMFSurveyView.swift: WMFComponents/Sources/WMFComponents/Components/Shared/Survey/WMFSurveyView.swift changed 2 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 15 in WMFSurveyView.body at line 49. 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-07-02..2026-09-30, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-07-02 17:30:08 -03:00\u0027 --until=\u00272026-09-30 17:30:08 -03:00\u0027 --full-history --no-merges -- WMFComponents/Sources/WMFComponents/Components/Shared/Survey/WMFSurveyView.swift\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":"WMFComponents/Sources/WMFComponents/Components/Shared/Survey/WMFSurveyView.swift"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"ce01ff762a92654758adf11fbb52fb73c059f55954c00a5be6358904f2ef5cd9"}},{"ruleId":"D16","level":"note","message":{"text":"Off-boarding risk: anonymized user #1: If anonymized user #1 becomes unavailable, 64 significant file(s) lose their only recent owner: Wikipedia/Code/WhichCameFirstCoordinator.swift, WMF Framework/ExploreCardCollectionViewCell.swift, Widgets/Widgets/OnThisDayView.swift, Wikipedia/Code/EvergreenAccountCreationCoordinator.swift, WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Core/WMFWhichCameFirstView.swift, WMFComponents/Sources/WMFComponents/Components/App Onboarding/WMFAppOnboardingStepViews.swift, WMFComponents/Sources/WMFComponents/Components/Games/Which Came First/Results/WMFWhichCameFirstResultsView.swift, WMFData/Sources/WMFData/Data Controllers/Evergreen Account Creation/WMFEvergreenAccountCreationDataController.swift (\u002B56 more). Pair on, review, or document these before any departure."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"740d4e1d1ef5a4a6da83d149c4de4ecefc2e84ccdc22e061e0adcdbc33aca468"}},{"ruleId":"D16","level":"note","message":{"text":"Off-boarding risk: anonymized user #2: If anonymized user #2 becomes unavailable, 30 significant file(s) lose their only recent owner: WMFComponents/Sources/WMFComponents/Components/Suggested Edits/Image Recommendations/WMFImageRecommendationsViewController.swift, WMFComponents/Sources/WMFComponents/Components/Editors/Common Views/Input Views/WMFEditorInputView.swift, Wikipedia/Code/FindAndReplaceKeyboardBar.swift, WMF Framework/ImageCacheController.swift, Wikipedia/Code/InsertMediaViewController.swift, WMFComponents/Sources/WMFComponents/Components/Shared/Page/WMFAsyncPageRowSaved.swift, WMF Framework/LocationManager.swift, Wikipedia/Code/UIViewController\u002BFeatureComponentFactory.swift (\u002B22 more). Pair on, review, or document these before any departure."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"20cc4de6a1d796a15d6279553a73ec2067569e6ee2203404ead1591037f10863"}},{"ruleId":"D16","level":"note","message":{"text":"Off-boarding risk: anonymized user #3: If anonymized user #3 becomes unavailable, 12 significant file(s) lose their only recent owner: WMFData/Sources/WMFData/Data Controllers/Donor Experience/WMFDonationReminderDataController.swift, WMFComponents/Sources/WMFComponents/Components/Donation Reminder/WMFDonationReminderSetupView.swift, Wikipedia/Code/NotificationsCenterCommonViewModel\u002BLinkExtensions.swift, Wikipedia/Code/ArticleScrolling.swift, WMF Framework/Widget/Models/WidgetFeaturedContent.swift, WMF Framework/String\u002BLinkParsing.swift, Wikipedia/Code/ChooseEditorSheetCoordinator.swift, WMF Framework/Widget/Models/WidgetCache.swift (\u002B4 more). Pair on, review, or document these before any departure."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"c5e15e410764a4c6a5975f5cbe687c3cfda53ea5c83193dfb280e3a7b3fa9b2c"}},{"ruleId":"D16","level":"note","message":{"text":"Off-boarding risk: anonymized user #4: If anonymized user #4 becomes unavailable, 6 significant file(s) lose their only recent owner: Wikipedia/Code/PageContentService\u002BUITestAccessibilityScript.swift, Wikipedia/Code/TestNetworkFixtures/TestNetworkFixtureStore.swift, Wikipedia/Code/TestNetworkFixtures/TestNetworkFixtureHTTPClient.swift, Wikipedia/Code/SessionHTTPClient.swift, Wikipedia/Code/TestNetworkFixtures/TestNetworkFixture.swift, Wikipedia/Code/TestNetworkFixtures/TestNetworkFixtureURLProtocol.swift. Pair on, review, or document these before any departure."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"842ad7c0d40f78f2276c0389b55a9d1f752f1b7e1936ad280e2168707933ffce"}},{"ruleId":"D16","level":"note","message":{"text":"Further sole-owners (lower concentration): 2 other contributor(s) are each the sole owner of a small amount of code below the off-boarding threshold \u2014 folded into the bus-factor score and metrics (114 single-owned of 687 analysed files in total, counted over production source files of roughly 2,400 bytes or more, excluding vendored, generated and example/demo trees and test files identified by path convention, largest first; 687 of the 1236 production source files in this repository met that bar). They are anonymized user #5 (1 file(s)), anonymized user #6 (1 file(s)) \u2014 spread or document their files in the same way, at lower priority than the named off-boarding risks above."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"6eac528f2429e724e1a97ed868f79eefbcf1888dab4af9a9e673429369bb5b2f"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: This is a temporary workaround to remove duplicated languages, but eventually a proper data migration for the user might need to occur to switch from the old language code to the new. \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":"Command Line Tools/Update Languages/WikipediaLanguageCommandLineUtilityAPI.swift"},"region":{"startLine":63}}}],"partialFingerprints":{"codehealthFindingId/v1":"41fc1a7bb3c386d82de4cbc42dc87093b377ed8600a96b415201de29688ca438"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Fix to work across languages, not just EN. Fetch special page aliases per site and add to a set of local json files. \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":"WMF Framework/Router.swift"},"region":{"startLine":75}}}],"partialFingerprints":{"codehealthFindingId/v1":"f5dadea174d25d499ed887a466074d67970606f47a451ad72cdcebfdb8a764ae"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: push history \u0027slice\u0027 \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":"WMF Framework/Router.swift"},"region":{"startLine":214}}}],"partialFingerprints":{"codehealthFindingId/v1":"7ebfe7564cf51a51db3de639657c2a2c42ec104af1e4c6e9a3e2f840748a29a5"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Remove when error response returns ID \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":"WMF Framework/ReadingListsAPIController.swift"},"region":{"startLine":317}}}],"partialFingerprints":{"codehealthFindingId/v1":"4972b296c260a367628f04bc4c5ad8a2fec838cb43fd885c22a43fd16a78e6ec"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Remove after moving to Swift 5.1 - \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":"WMF Framework/NavigationState.swift"},"region":{"startLine":85}}}],"partialFingerprints":{"codehealthFindingId/v1":"17ec4315a2bcea66a0dc64cb790817fe9677b1fd3af8e9eb629f2e6eecbac084"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Remove these helpers after \u0060WMFNearbyContentSource\u0060 is refactored to Swift and \u0060LocationManager\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":"WMF Framework/LocationManagerProtocol.swift"},"region":{"startLine":3}}}],"partialFingerprints":{"codehealthFindingId/v1":"412e268074c8fe77287ba5633e3cb036bd69e83b98aba6fe37ab43a4d85dd372"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo: could use DRY gatekeeper logic with superclass. this will likely get refactored out so holding off. \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":"WMF Framework/ImageCacheController.swift"},"region":{"startLine":13}}}],"partialFingerprints":{"codehealthFindingId/v1":"5fc570c0e9c0b403c5dccf1c3d6ec8583525ae4e3d00b15fba745fe5e1ac39a8"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Standardize on returning CancellationKey or URLSessionTask \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":"WMF Framework/Fetcher.swift"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"7b9cee0ed4b4fbbbbf7c967f894ad76338caa08c3e3ee7e35a5eb47a1591783f"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Centralize cancellation and remove other cancellation implementations (ReadingListsAPI) \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":"WMF Framework/Fetcher.swift"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"30cdf59f16b277ae4a4b26cfc25a482ad2949ff65b328dd79795534c2d807c42"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Think about utilizing a request buildler instead of so many separate functions \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":"WMF Framework/Fetcher.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"e67dc453c7a8326047dfaaaef485ffe5bc85c489d1c108c92c3149f09543a74f"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Utilize Result type where possible (Swift only) \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":"WMF Framework/Fetcher.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"f67a997b9af62aee4ea38f18325e1c4ccaf47f94dc7e041e94a38cd0a7f62aea"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: less of a sledgehammer here \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":"WMF Framework/CacheTaskTracking.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"5f4abc2681487f7242896d4cc0f44a61261f3155c5898bfd8ed92f2fe3b27580"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo: Settings hook, logout don\u0027t sync hook, etc. \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":"WMF Framework/CacheController.swift"},"region":{"startLine":37}}}],"partialFingerprints":{"codehealthFindingId/v1":"26b21d55d9494766cef4f4ee700003970c46d2841f25f560237aa7574e0f92d2"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: This would be better as a generated mapping file from translatewiki\u0027s project translations (for example: https://translatewiki.net/wiki/Special:ExportTranslations?group=ext-wikimediaprojectnames\u0026language=he\u0026format=export-to-file)"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/Remote Notifications/Model/WikimediaProject\u002BRemoteNotifications.swift"},"region":{"startLine":89}}}],"partialFingerprints":{"codehealthFindingId/v1":"6432b4c76122c9571d0bd0d365e5c3fefa5c175f6e322c77351318600c19f058"}},{"ruleId":"D17","level":"warning","message":{"text":"HackComment: // HACK: Forces liquid glass bar button items to re-render with correct appearance. \u2014 a workaround marked in source: record what it is compensating for and what would allow its removal (the upstream fix, the API it is waiting on, the invariant it restores), so the next reader can judge whether it is still needed rather than rediscovering why it is there."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Base/Component Base Classes/WMFComponentNavigationController.swift"},"region":{"startLine":52}}}],"partialFingerprints":{"codehealthFindingId/v1":"999ded23d8cc60cfa40235bdd324dca3bfec0785304584fda9f5653812c4d70e"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Error 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":"WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/Your Interests/WMFHomeFeedInterestsSettingsViewModel.swift"},"region":{"startLine":339}}}],"partialFingerprints":{"codehealthFindingId/v1":"82cf4ee6447a3abe406de30c3b69aca5edd174c88e70cca8a517606887c0fd95"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Error 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":"WMFComponents/Sources/WMFComponents/Components/Settings/Home/For You/Whats Driving/Your Interests/WMFHomeFeedInterestsSettingsViewModel.swift"},"region":{"startLine":355}}}],"partialFingerprints":{"codehealthFindingId/v1":"69bc482142b4516e847b6f3ea583341878d261041d3101a7e41b61a0492f5e2f"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Consider smarter prefix amounts, depending on screen size. \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":"WMFComponents/Sources/WMFComponents/Extensions/Navigation Bar/WMFNavigationBarConfiguring.swift"},"region":{"startLine":177}}}],"partialFingerprints":{"codehealthFindingId/v1":"827a2f97641161b6732df748fc407967380012c06d695c0d50884f0c26d25c8f"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Remove when the \u0060iosv1.semanticSearchLanguages\u0060 in the remote feature config is available. \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":"WMFData/Sources/WMFData/Data Controllers/Semantic Search/WMFSemanticSearchDataController.swift"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"236b5caca5ac34dd8ba3e286ee2faf3b14475ffe7cf99fa825c04ac9bde578cc"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Remove this file when the 2026 entry is published on wikifeeds. \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":"WMFData/Sources/WMFData/Data Controllers/Year In Review/WMFYearInReviewLocalConfig.swift"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"4fa3101fab7b6bd489a11c745b6d5277c8121d9fbe6f16e7ff1ccbb094dcdc9d"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: 2026 \u2014 if there is a 2026 app icon, this needs its own key alongside \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":"WMFData/Sources/WMFData/Data Controllers/Year In Review/WMFYearInReviewDataController.swift"},"region":{"startLine":767}}}],"partialFingerprints":{"codehealthFindingId/v1":"c6f3699b5503e22db84e6f829f6fc01e45555e493cb9bc07410819237d864a6e"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Once the Wikipedia app target has been migrated to Swift 6 and its launch-time \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":"WMFData/Sources/WMFData/Environment/WMFDataEnvironment.swift"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"b007769b84e925ac709b56516860bff7e1bfdec328dee37d2067f18671f00d19"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo \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":"WMFData/Sources/WMFDataMocks/WMFMockArticleTabsDataController.swift"},"region":{"startLine":23}}}],"partialFingerprints":{"codehealthFindingId/v1":"577d33282af2453c33c95e0dfcb53a78f39513ea79643baa1e184e167b903555"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo \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":"Wikipedia/Code/WMFContentGroup\u002BDetailViewControllers.swift"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"f64a435d2c55562a8929801b7859228b36288d7d2a3ceb7fc387ca893778aef0"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo \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":"Wikipedia/Code/WMFContentGroup\u002BDetailViewControllers.swift"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"7c46cfe353c523e2c13548a7b1fad8d35ddde55748f206221aab81b98cd5fa3d"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo: \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":"WMFData/Sources/WMFDataMocks/WMFMockArticleTabsDataController.swift"},"region":{"startLine":190}}}],"partialFingerprints":{"codehealthFindingId/v1":"c599d071189c69287c872d1a44690bed6ee9f1b34156b6ed1983c5487ce4b696"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Delete this when we remove web editor code \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":"WMFLocalizations/Sources/WMFNativeLocalizations/CommonStrings.swift"},"region":{"startLine":198}}}],"partialFingerprints":{"codehealthFindingId/v1":"23746b1638fe763f93b20c5626862a64cc8e201a3054fe1e00f72c853b19710e"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Delete this when we remove web editor code \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":"WMFLocalizations/Sources/WMFNativeLocalizations/CommonStrings.swift"},"region":{"startLine":527}}}],"partialFingerprints":{"codehealthFindingId/v1":"ee2e954b388144ba1297bc52b01c044cbe0c939ee7b5be2c73d4628bd1e7e82b"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Apply shadow just to final content \u2013 not children views as well \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":"Widgets/Widgets/TopReadWidget.swift"},"region":{"startLine":375}}}],"partialFingerprints":{"codehealthFindingId/v1":"f448d30fe4b429f35b18c5d86d6a908e4b140142c5327204e280b698c925f274"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Fix duplication \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":"Wikipedia/Code/WMFReferencePageViewController.swift"},"region":{"startLine":31}}}],"partialFingerprints":{"codehealthFindingId/v1":"1e0e593cf7a84ef64d06bf085fc8366d3a163ead1b6f2b0712ac24140a88a423"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Fix duplication \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":"Wikipedia/Code/ReferenceShowing.swift"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"98d233b3b17059a9e00cd206b1a2703d2946c0f0bfeff4cbddc5458a007b65b9"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo: pass in article source Explore \u003E Nearby 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":"Wikipedia/Code/WMFContentGroup\u002BDetailViewControllers.swift"},"region":{"startLine":61}}}],"partialFingerprints":{"codehealthFindingId/v1":"ef06ba2ea3384170113e34da0feaa6ad0bba089eb54b5f5d1bf169768d047e1a"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Remove the legacy welcome flow once the new home feed onboarding ships unflagged. \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":"Wikipedia/Code/WMFAppViewController.swift"},"region":{"startLine":1694}}}],"partialFingerprints":{"codehealthFindingId/v1":"7cb683f7c7c7d6153ee6a1235cbd86cdde9183ea796910c62b9a1a336689aa1f"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Allow if NOT temp accounts pilot wiki \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":"Wikipedia/Code/TalkPageTopicComposeViewController.swift"},"region":{"startLine":559}}}],"partialFingerprints":{"codehealthFindingId/v1":"23dda1d07e230423d0488f6dfe50a3b26b5c15a54efb94c0b95829b468744323"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Allow if NOT temp accounts pilot wiki \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":"Wikipedia/Code/TalkPageReplyComposeController.swift"},"region":{"startLine":426}}}],"partialFingerprints":{"codehealthFindingId/v1":"10793da57ae5de87fe849e991dd127296d029f80109cfa550c79db0667aea67a"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Clean up these DB inconsistencies in the DatabaseHousekeeper \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":"Wikipedia/Code/SavedArticlesFetcher.swift"},"region":{"startLine":275}}}],"partialFingerprints":{"codehealthFindingId/v1":"b534652c139f02eb7f85d942f68c5c80db3d53e4a902ea4ca06132874e2381f0"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo: share localizations \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":"Wikipedia/Code/ProfileCoordinator.swift"},"region":{"startLine":195}}}],"partialFingerprints":{"codehealthFindingId/v1":"0069af4154fba2912995c65aa7cd64208bf0828f76056f0441c6c569af4ed627"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: remember last setting? \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":"Wikipedia/Code/PlacesViewController.swift"},"region":{"startLine":1230}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c3e51374859e55e4bbd8a73ab3267d4cd965f7501533100bc6fb28555cc1f03"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: make non-optional? \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":"Wikipedia/Code/PlaceSearchService.swift"},"region":{"startLine":17}}}],"partialFingerprints":{"codehealthFindingId/v1":"daaf0544e5e63fd6ce300d7f9b444c242a4b103534f2a3ebdfdaf0c723adf84f"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: get rid of this when the VC is swift and we can use default values in the other init \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":"Wikipedia/Code/PageHistoryFetcher.swift"},"region":{"startLine":315}}}],"partialFingerprints":{"codehealthFindingId/v1":"9ce190463ed027d94d3dfd0f3f0ea1fd78e5ffa3a38ee7ddc57e444e85e5ece4"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Make sure all icons have the same sizes \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":"Wikipedia/Code/PageHistoryCollectionViewCell.swift"},"region":{"startLine":256}}}],"partialFingerprints":{"codehealthFindingId/v1":"74c6791f110fef65f857c62e31c0a8080fbbec2d61b4239632a344cfc80146a8"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo: may want to shift this higher or lower depending on screen size. Also possibly give it a max value \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":"Wikipedia/Code/OldTalkPageReplyCell.swift"},"region":{"startLine":43}}}],"partialFingerprints":{"codehealthFindingId/v1":"17c887adb6b49104cf2c6e4b8c2d6b0ae88ce9262d859c26e0f17ccdd7e621d9"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo: we may want to switch to get article source if we want to be more specific: \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":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":865}}}],"partialFingerprints":{"codehealthFindingId/v1":"fa2ef6b24885815f19f9736020d5a60a10f09bb1403ef11131cf4dc90f24fc87"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo: we may want to switch to get article source if we want to be more specific: \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":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":879}}}],"partialFingerprints":{"codehealthFindingId/v1":"4e66d9d3302c327e62bbfc59c6ae202699891776e59f1570e32177c9766e8ccd"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: 2026 \u2014 swap \u0060yirCoordinator\u0060 for the 2026 coordinator. It needs to know it was \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":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":1251}}}],"partialFingerprints":{"codehealthFindingId/v1":"464cf89885b6fd8b16bcd8661d197de805da8f5f0388e818694bbfe0ab2d7bf2"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: 2026 \u2014 swap \u0060yirCoordinator\u0060 for the 2026 coordinator. It needs to know it was \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":"Wikipedia/Code/ArticleViewController\u002BAnnouncements.swift"},"region":{"startLine":274}}}],"partialFingerprints":{"codehealthFindingId/v1":"c06178bf15723c4113cd2ddc5c799275957c7befe137c2440c923d124c6c92e4"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo: confirm commas don\u0027t get cut off \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":"Wikipedia/Code/EditInteractionFunnel.swift"},"region":{"startLine":314}}}],"partialFingerprints":{"codehealthFindingId/v1":"c059d9eddf9d16f7e6e3c7dc92d4a7662208c65bd5477780754e22071cdb2309"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // todo: fix logging source, custom tab config? .appendArticleAndAssignCurrentTabAndCleanoutFutureArticles \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":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":961}}}],"partialFingerprints":{"codehealthFindingId/v1":"148022076f6e8d6f9995747b04b7ecb4d3cd73ec0882361eced0eb4be550cbef"}},{"ruleId":"D17","level":"warning","message":{"text":"HackComment: // HACK: Sometimes the \u0060scroll_to_anchor\u0060 message is not triggered from the web view over the JS bridge, even after prepareForScrollToAnchor successfully goes through. This means the completion block above is queued to scrollToAnchorCompletions but never run. We are trying to scroll again here once more after a slight delay in hopes of triggering \u0060scroll_to_anchor\u0060 again. \u2014 a workaround marked in source: record what it is compensating for and what would allow its removal (the upstream fix, the API it is waiting on, the invariant it restores), so the next reader can judge whether it is still needed rather than rediscovering why it is there."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleViewController.swift"},"region":{"startLine":1050}}}],"partialFingerprints":{"codehealthFindingId/v1":"194898c0163f1eb295706839ccd13a856e41a833f1ceeaac98cf801614513a53"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Restore URLQueryItem(name: \u0022returntoapp\u0022, value: \u00221\u0022) once the web\u0027s tap-to-return \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":"Wikipedia/Code/ArticleViewController\u002BEditing.swift"},"region":{"startLine":99}}}],"partialFingerprints":{"codehealthFindingId/v1":"02daf528dbc3a9eb9ad5d5ccfbb064f215c6287564028edf0200dcffeca09e54"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Refactor background task refresh and notification token registration logic out of WMFAppViewController. Then we can then move tab bar instantiation into SceneDelegate. \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":"Wikipedia/Code/AppDelegate.swift"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"e33defbb2e28145ca32625ea338e9fe6763ff908bb1b8d1d7970ed17e6e8dc8d"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: // TODO: Will probably need some special logging here. \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":"Wikipedia/Code/ActivityTabViewController.swift"},"region":{"startLine":259}}}],"partialFingerprints":{"codehealthFindingId/v1":"c108b9bc9c83aca0b30b2f57d095daebb973516f0f9b6427ebbf8daff6f13383"}},{"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":"Redundant lifecycle method across component types. While these are distinct types, the method \u0060appEnvironmentDidChange\u0060 appears on 5 different component-related types with identical signatures and likely identical implementation logic (reacting to theme/trait changes). This suggests a shared protocol or base class could unify this behavior, reducing boilerplate and ensuring consistent handling of environment changes across the component hierarchy.: Extract \u0060appEnvironmentDidChange()\u0060 into a common protocol (e.g., \u0060EnvironmentAwareComponent\u0060) or a base class that all these component types inherit from or conform to. (signatures: WMFComponentHostingController.appEnvironmentDidChange() | WMFComponentNavigationController.appEnvironmentDidChange() | WMFComponentView.appEnvironmentDidChange() | WMFComponentViewController.appEnvironmentDidChange() | WMFCanvas.appEnvironmentDidChange())"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"827f57ca2b3fca7013b0565312708346c2ccbf9dbecdd94787fd5c530ee7a070"}},{"ruleId":"D26","level":"note","message":{"text":"Split WMFComponents: At 32k LoC the component assembly is large but its 68 namespaces are all sources under WMFComponents/Sources/WMFComponents/* and should be treated as one unit. Suggested: "},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"891b878c97bf8abff23a160a5f7665c52cb955797f7906d4c4b820fd16dcff48"}},{"ruleId":"D28","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":"54e68c29f5e0c73a9fc9b7149c61b550629af591f97fb43c2ecff0bd1db20a1e"},"properties":{"commitSha":"f73d7af46253afdabfa69b334a468dc963eb07d9"}},{"ruleId":"D28","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":"39f36beb4f34b2ccffafc1606f69685207748dc9a944cf9329337121630c8ca5"},"properties":{"commitSha":"9022dbc66874e374504f76db1f23706a111bc9fd"}},{"ruleId":"D28","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":"3c39688b0337a50b137d8bfa37949a5a90934f26e1cc0abddf1a5d937bdbfcaf"},"properties":{"commitSha":"d5da47860f311783c8f2729b8975ca431f985c41"}},{"ruleId":"D28","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":"1c1506b017c746738e1704d0f4b4ca75e1910d80cf340da384bf18e8980d112e"},"properties":{"commitSha":"d5da47860f311783c8f2729b8975ca431f985c41"}},{"ruleId":"D28","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":"68693b39d6aaa32c1701f17ee9626ab84f78e88dee2918c11ec7140ff52fd1a6"},"properties":{"commitSha":"3ad4f437b565de69bdad09e624b17f4676dc52ba"}},{"ruleId":"D28","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":"54c985992e8e0333da99fd357b8f2f0dd63d1cf1247eb25ddde7e4ae825d7c7d"},"properties":{"commitSha":"65dcedf69c056cbdb25bc940eaad28d2c587aebc"}},{"ruleId":"D28","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":"b40abba1b9553333ceb331ff0eacbb6b9de16394671ed9c352cd8b885868a5e4"},"properties":{"commitSha":"49e7f348508a4ca99e0075fc5293e302d562267c"}},{"ruleId":"D28","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":"3e69fbd5406e25261955eaeceb673e798b4faaf195d931b8135fc9662a636d01"},"properties":{"commitSha":"cefce71b95bd4341a4eeed04bd795a48b4e89645"}},{"ruleId":"D28","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":"409fdc98688b0c474bbac24440d3795a0388181a0555b43155005a907ef976a0"},"properties":{"commitSha":"17a24b92296a66ca0b0c32fbf14c43a17ae7e7a8"}},{"ruleId":"D28","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":"6559280bb02741fdc264c246b2e3bc2b96d34aeb38f8bfd0715337e2d0fc90d1"},"properties":{"commitSha":"17a24b92296a66ca0b0c32fbf14c43a17ae7e7a8"}},{"ruleId":"D28","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":"eaf408d38f6ce861f007c3ae51997103523bdf4dfb10b21aae56cbea7dd6054f"},"properties":{"commitSha":"346aae47b5628b98a59e9ba2b68722b51487d48f"}},{"ruleId":"D28","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":"1e86b84176165f304fdaaf2307998611ba0767abfe9cd0251d32dafe4b39c9d6"},"properties":{"commitSha":"c60e8e70a6cc8fa6faf591d542b6048104fd99d4"}},{"ruleId":"D28","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":"3cdfd7beb31b791ae18dcb425e21eb157c842e7bbcd522cc330573c1a6538db1"}},{"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":"d8107303423ed5025f63e0fdc76cf8ea6c62473b99ea22611fc3c75615da7c09"},"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":"0c3ac9b5a8cd8a3c3623106171dbde010fd485ac5bd59b2fb67d8ed83cb02e07"},"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":"cb324dad5c0edfec2409163c54a3edd5508aec4c4bc0c6e20cd1eb467cac7353"},"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":"23f967a10954821288ce79ec260a7da0a385641e52bdcb56f41e844353b05300"},"taxa":[{"id":"CWE-214","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-532","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":"9810bd1d466cc1e84ee1f8ca59d72ce750758ab027e8fb6a3f64ef9f844b812c"},"taxa":[{"id":"CWE-522","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-668","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":"038aedb2b0f38d569ede29bdfa945595c75dcfaaa7f50f23d49754390957ecf6"},"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":"7f2cd26fae601606fa882162b845209dbff3b24e5d625c4f087a6b9ecc675ae6"},"taxa":[{"id":"CWE-214","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-532","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":"e26a3231c1ab6fc9318791ddbce3d7119737bdd68a12fefec0c435299045dffe"},"taxa":[{"id":"CWE-522","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-668","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":"f41839f357e4345b82127fba35d3ad43ba3b745c012b3ff5358b5935e09dc98d"},"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":"1d2a50aa2b8061af7ed72492bc3cfbc6ee1c8b8982b82a2586b9f28d091baf12"},"taxa":[{"id":"CWE-214","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-532","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":"519258b7f9d0df4b87c8e7a58c8f5bf102c3669e933d8924560e3a245502ba79"},"taxa":[{"id":"CWE-522","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-668","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":"31f06ac0e7f48b4b6fb81af4d9c07a98a909549f7384d19ae32142e86ca30640"},"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":"c709fa8804d42c3ddb4d0402f56ef207a3b04e63b3053a9d6d5443502f4c529e"},"taxa":[{"id":"CWE-214","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-532","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":"ab76614e8de4f159b814da2bcb5658560ca340e21062fbf9c4239993d16bdd57"},"taxa":[{"id":"CWE-522","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-668","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":"47fa07f4a3a97d22efc57d90fbadece4060b6aa2b6700e3d4f6d9d023caf7bbe"},"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":"a79870ad39ba65acdbb0592aadfbc9bd40c1b7214641d983d60115b03c617f15"},"taxa":[{"id":"CWE-214","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-532","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":"d8829d422cd38e89ea0ea2976e745147f789d893f3c4b9176a4943c1f2054294"},"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":"e4e21d1baa42c3f9a7fb27a37e0bbaf66c25ff0d84e3712093ab97249e0e193c"},"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":"c164e34ca93624bcac9f61b678c27eb2300ec777dc2d5990e01bdfa6f0ec9efa"},"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":"6292b3751576fdeafc8264dcc609864effca5dcf3c9236bfc057cfaa6f862ba2"},"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":"b75f19f3c8e0645cf7ae56465d925a9cf4d8388c63f2ca4bbb752f44e7388a3d"},"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":"8de50c2f014865193cc95095e87d4793ce138dfc6989f19d811102d30d6d24b3"},"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":"c64c9fd4c5f9e933f5b700ddce10471567b6cd740443bea7d9d571d16cd656c6"},"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":"6b0a85ce85b3ed80e11df3cbd22d1f7709d8d9badfadf3decf91b3ee2a6f5ebf"},"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":"dec0f0c2a06843a267f962620294346e84bc748832e257116f1f87a04ed9fb44"},"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":"66b9b6d45ef6013fa35341db19cc73e749edc62673a1a2034e0c47f8d3474cac"},"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":"6e79444b370c88cc1dc242a994e2a2f11a87ac41084a8066271d65662925e4fb"},"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":"e07e6b9fd142cda2658a94dfb8f569dca30ffaa4f4f3771466e2a78962c7e68e"},"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":"39d1ade672e143b1ceb281078a786eb1f930f69ca2a5810555af250109a928f9"},"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":"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":"d1d43c1fec11e5e5ab9e22afda43635e767b74c8cac7adefae33ea918e98a56b"},"taxa":[{"id":"CWE-134","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-943","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","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":"5622e27ad4b6f3f4da8478ace765f3b79220f5be80b105cff390952ff2222343"},"taxa":[{"id":"CWE-134","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-943","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","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":"1ba6204207403b3f7836cbf7fbc29492338b9bf7d6b2dedfc630e571c07355fe"},"taxa":[{"id":"CWE-134","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-943","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","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":"7757d133c8b0db6be124e537d2daba18bcb485448f7a67306ce51cd9d440bf32"},"taxa":[{"id":"CWE-457","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","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":"2b412932d375cf870297635325daa90b7f9b1be1604c5af380769fe75839a525"},"taxa":[{"id":"CWE-319","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","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":"7771ed10c2e41347fa4f91c6b849f9fcb22de34d9f63ae5b6f3f4c68106434ea"},"taxa":[{"id":"CWE-319","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","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":"a2f0db9edb5c8c8f0bc5fc6be5adcbf8cacab33d884469e5767cc52ffd15619c"},"taxa":[{"id":"CWE-319","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","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":"98f90daeb3d2fa0314a7b1ef228b2495eca1e6b79ad5b1a3cbe03b1345e29de8"},"taxa":[{"id":"CWE-319","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":"cdd0a7ecc16332535f869a4c0d6fabd5d6770567695cd122fe55c8e4fc586bae"},"properties":{"dependency":{"package":"rubyzip","version":"2.4.1","advisory":"[GHSA redacted]","aliases":["[CVE 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":"3acf461327c8d5eb139fb28055eb092d4d60f44d473a75aff035039585d5f410"},"properties":{"dependency":{"package":"excon","version":"1.2.5","advisory":"[GHSA redacted]","aliases":["[CVE redacted]"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D30","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":"6ffc2ba2fbc85e5c760d1bb5284325c61454b704b0b774f8b84fb41a6faab4ed"},"properties":{"dependency":{"package":"json","version":"2.21.1","advisory":"[GHSA redacted]","aliases":["[CVE redacted]"],"reachability":{"kind":"unknown"}}}},{"ruleId":"D34","level":"error","message":{"text":"Orphaned knowledge: No living knowledge remains for this large file \u2014 its last meaningful change has decayed away; if it breaks, no one currently understands it. Schedule a read-through / add characterisation tests before it bites."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/NotificationsCenterCell.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"6a5322255f98606035d3f06821a9527f0c7e98d2fd2a46a156437c1e069e94af"}},{"ruleId":"D34","level":"note","message":{"text":"Further orphaned files (smaller): 53 smaller file(s) also have no living knowledge \u2014 folded into the freshness score and metrics rather than raised one row each \u2014 most significant first: Wikipedia/Code/TableOfContentsAnimator.swift, Widgets/Widgets/OnThisDayWidget.swift, Wikipedia/Code/PageHistoryCollectionViewCell.swift, WMF Framework/ColumnarCollectionViewLayout.swift, Wikipedia/Code/QuadKey.swift, Wikipedia/Code/NSLocale\u002BWMFExtras.swift, WMF Framework/ColumnarCollectionViewLayoutInfo.swift, WMF Framework/UIView\u002BSemanticContent.swift (and 45 more) (54 orphaned of 690 analysed files in total, counted over production source files of roughly 2,400 bytes or more, excluding vendored, generated and example/demo trees and test files identified by path convention, largest first; 690 of the 1236 production source files in this repository met that bar). Attach the read to the next change that touches one of them: have a second person review that change, and leave behind a short comment or test recording what the file is for, so the knowledge comes back at the cost of a change you were making anyway."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"ce861fd78f6935114d3a342cb90ad25870f984e1042954fcbbe27c0e23be3658"}},{"ruleId":"D35","level":"error","message":{"text":"Boundary-crossing change coupling: WMFDeveloperSettingsView.swift \u2194 WMFDeveloperSettingsDataController.swift: \u0060WMFComponents/Sources/WMFComponents/Components/Developer Settings/WMFDeveloperSettingsView.swift\u0060 (context WMFComponents) and \u0060WMFData/Sources/WMFData/Data Controllers/Developer Settings/WMFDeveloperSettingsDataController.swift\u0060 (context WMFData) sit in DIFFERENT parts of the tree yet change together 78% of the time (29 of the 37 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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) \u2014 the bounded-context boundary may be in the wrong place, or one context is leaking into the other. This is the behavioural boundary violation a static scan can\u0027t see. You can check this without leaving the row: of the 29 shared commits counted here, the most recent 3 are \u0060c9ce202d\u0060 Remove games dev settings; \u0060b37d1391\u0060 Create YiR dev settings section; \u0060bab87769\u0060 Add the semantic search experiment and its developer settings \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Developer Settings/WMFDeveloperSettingsView.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"69d414b9d3ffc65a03161659d00f7c8fd3b56fea90f6559c16d5d7f913327a4d"}},{"ruleId":"D35","level":"error","message":{"text":"Boundary-crossing change coupling: WMFDeveloperSettingsView.swift \u2194 WMFUserDefaultsKey.swift: \u0060WMFComponents/Sources/WMFComponents/Components/Developer Settings/WMFDeveloperSettingsView.swift\u0060 (context WMFComponents) and \u0060WMFData/Sources/WMFData/Store/WMFUserDefaultsKey.swift\u0060 (context WMFData) sit in DIFFERENT parts of the tree yet change together 65% of the time (24 of the 37 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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) \u2014 the bounded-context boundary may be in the wrong place, or one context is leaking into the other. This is the behavioural boundary violation a static scan can\u0027t see. You can check this without leaving the row: of the 24 shared commits counted here, the most recent 3 are \u0060c9ce202d\u0060 Remove games dev settings; \u0060bab87769\u0060 Add the semantic search experiment and its developer settings; \u006033fb335d\u0060 Add a fundraising date override to the developer settings \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Developer Settings/WMFDeveloperSettingsView.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"1c2008a0b45ff73830a9d53aa31b9278395104ea92e53b3adec5121ae3458385"}},{"ruleId":"D35","level":"error","message":{"text":"Boundary-crossing change coupling: WMFTempAccountsSheetView.swift \u2194 EditorViewController.swift: \u0060WMFComponents/Sources/WMFComponents/Components/Temp Accounts/WMFTempAccountsSheetView.swift\u0060 (context WMFComponents) and \u0060Wikipedia/Code/EditorViewController.swift\u0060 (context Wikipedia) sit in DIFFERENT parts of the tree yet change together 62% of the time (8 of the 13 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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) \u2014 the bounded-context boundary may be in the wrong place, or one context is leaking into the other. This is the behavioural boundary violation a static scan can\u0027t see. You can check this without leaving the row: of the 8 shared commits counted here, the most recent 3 are \u0060549364a3\u0060 Sheet buttons, profile view model fix; \u00607a5ff8a7\u0060 Move editor presentation logic, remove unused variable; \u006042fd1af8\u0060 PR fixes \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Temp Accounts/WMFTempAccountsSheetView.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"b8842db3238bf580208933fd316ea1ecbe4bca8ec4c7bc12de315336149f47c1"}},{"ruleId":"D35","level":"error","message":{"text":"Boundary-crossing change coupling: WMFDeveloperSettingsViewModel.swift \u2194 WMFMockDeveloperSettingsDataController.swift: \u0060WMFComponents/Sources/WMFComponents/Components/Developer Settings/WMFDeveloperSettingsViewModel.swift\u0060 (context WMFComponents) and \u0060WMFData/Sources/WMFDataMocks/WMFMockDeveloperSettingsDataController.swift\u0060 (context WMFData) sit in DIFFERENT parts of the tree yet change together 60% of the time (21 of the 35 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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) \u2014 the bounded-context boundary may be in the wrong place, or one context is leaking into the other. This is the behavioural boundary violation a static scan can\u0027t see. You can check this without leaving the row: of the 21 shared commits counted here, the most recent 3 are \u0060b37d1391\u0060 Create YiR dev settings section; \u00607e1cd722\u0060 Spacing; \u0060ad82e504\u0060 Start dev settings \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Developer Settings/WMFDeveloperSettingsViewModel.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"76cd5a1e13e30ff2a01b18eb887fc34149ea0fba4903a6a368fd5cc2dfbadeb6"}},{"ruleId":"D35","level":"error","message":{"text":"Boundary-crossing change coupling: WMFSavedAllArticlesView.swift \u2194 SavedAllArticlesCoordinator.swift: \u0060WMFComponents/Sources/WMFComponents/Components/Saved/All Articles/WMFSavedAllArticlesView.swift\u0060 (context WMFComponents) and \u0060Wikipedia/Code/SavedAllArticlesCoordinator.swift\u0060 (context Wikipedia) sit in DIFFERENT parts of the tree yet change together 60% of the time (9 of the 15 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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) \u2014 the bounded-context boundary may be in the wrong place, or one context is leaking into the other. This is the behavioural boundary violation a static scan can\u0027t see. You can check this without leaving the row: of the 9 shared commits counted here, the most recent 3 are \u00609ca84168\u0060 Add missing Saved All Articles events; \u0060873779e9\u0060 Add back in delete prompt (at that commit the files were still \u0060WMFComponents/Sources/WMFComponents/Components/Saved/All Articles/WMFAllArticlesView.swift\u0060 and \u0060Wikipedia/Code/AllArticlesCoordinator.swift\u0060); \u00609d91d931\u0060 Add login to sync prompt (at that commit the files were still \u0060WMFComponents/Sources/WMFComponents/Components/Saved/All Articles/WMFAllArticlesView.swift\u0060 and \u0060Wikipedia/Code/AllArticlesCoordinator.swift\u0060) \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Saved/All Articles/WMFSavedAllArticlesView.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"b7cfd1ee91c84e9b5188bfd10fb9093dce6189df9fe0c6aa8c2e4a61f52e1c0e"}},{"ruleId":"D35","level":"error","message":{"text":"Boundary-crossing change coupling: WMFYearInReviewView.swift \u2194 YearInReviewCoordinator.swift: \u0060WMFComponents/Sources/WMFComponents/Components/Year in Review/WMFYearInReviewView.swift\u0060 (context WMFComponents) and \u0060Wikipedia/Code/YearInReviewCoordinator.swift\u0060 (context Wikipedia) sit in DIFFERENT parts of the tree yet change together 56% of the time (20 of the 36 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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) \u2014 the bounded-context boundary may be in the wrong place, or one context is leaking into the other. This is the behavioural boundary violation a static scan can\u0027t see. You can check this without leaving the row: of the 20 shared commits counted here, the most recent 3 are \u00602e92f1a6\u0060 Rework mock to location slide; \u00603b51ec32\u0060 Finish refactor for category slide; \u00603dc72266\u0060 Alt text \u002B imagery touchups \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Year in Review/WMFYearInReviewView.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"d7eeae53288ac29adc3bcf65a009cf7df4122c6d4df2e4f1cccc87ac450a3597"}},{"ruleId":"D35","level":"error","message":{"text":"Boundary-crossing change coupling: WMFDonateViewController.swift \u2194 SinglePageWebViewController.swift: \u0060WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewController.swift\u0060 (context WMFComponents) and \u0060Wikipedia/Code/SinglePageWebViewController.swift\u0060 (context Wikipedia) sit in DIFFERENT parts of the tree yet change together 55% of the time (6 of the 11 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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) \u2014 the bounded-context boundary may be in the wrong place, or one context is leaking into the other. This is the behavioural boundary violation a static scan can\u0027t see. You can check this without leaving the row: of the 6 shared commits counted here, the most recent 3 are \u00600fe227e5\u0060 Fix iPad contributions bar configuration; \u00600562adf0\u0060 Progress with reworking cancel and done buttons; \u0060ca67d258\u0060 Updates the cancel action to use cancel text, keep it on the leading \u2026 \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Donate Form/WMFDonateViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"e9d3de72c2782c1757edafe80988750d257ed543eb059a2ca0a9c13ee2f40d17"}},{"ruleId":"D35","level":"error","message":{"text":"Boundary-crossing change coupling: WMFYearInReviewSlide.swift \u2194 YearInReviewCoordinator.swift: \u0060WMFData/Sources/WMFData/Models/Year In Review/WMFYearInReviewSlide.swift\u0060 (context WMFData) and \u0060Wikipedia/Code/YearInReviewCoordinator.swift\u0060 (context Wikipedia) sit in DIFFERENT parts of the tree yet change together 53% of the time (9 of the 17 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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) \u2014 the bounded-context boundary may be in the wrong place, or one context is leaking into the other. This is the behavioural boundary violation a static scan can\u0027t see. You can check this without leaving the row: of the 9 shared commits counted here, the most recent 3 are \u0060abd983af\u0060 Add time, month calculations and add standard slide; \u00608e1b9e6c\u0060 Top articles slide; \u0060730ec126\u0060 Fix compile failures, delete unnecessary evaluated flag \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Models/Year In Review/WMFYearInReviewSlide.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"3feae0b9897a1b549b60d0182d098cbd62d028b1fe888c8186e1dd1a6cbb7c36"}},{"ruleId":"D35","level":"error","message":{"text":"Boundary-crossing change coupling: WMFFeatureAnnouncementView.swift \u2194 ExploreViewController.swift: \u0060WMFComponents/Sources/WMFComponents/Components/Shared/Feature Announcement/WMFFeatureAnnouncementView.swift\u0060 (context WMFComponents) and \u0060Wikipedia/Code/ExploreViewController.swift\u0060 (context Wikipedia) sit in DIFFERENT parts of the tree yet change together 50% of the time (11 of the 22 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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) \u2014 the bounded-context boundary may be in the wrong place, or one context is leaking into the other. This is the behavioural boundary violation a static scan can\u0027t see. You can check this without leaving the row: of the 11 shared commits counted here, the most recent 3 are \u006075ef9f85\u0060 Dinamically calculate background image height; \u006072a539e2\u0060 Combine announcements into one coordinator; \u0060d86c63ea\u0060 Update feature announcement components and ExploreViewController \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Shared/Feature Announcement/WMFFeatureAnnouncementView.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"2ba041e97dabaafa0c0784c16621f322ad8e30dffaabfacdfc59b2565e7784b7"}},{"ruleId":"D35","level":"error","message":{"text":"Boundary-crossing change coupling: SettingsCoordinatorDelegate.swift \u2194 WMFAppViewController\u002BExtensions.swift: \u0060WMFComponents/Sources/WMFComponents/Coordinator/SettingsCoordinatorDelegate.swift\u0060 (context WMFComponents) and \u0060Wikipedia/Code/WMFAppViewController\u002BExtensions.swift\u0060 (context Wikipedia) sit in DIFFERENT parts of the tree yet change together 50% of the time (9 of the 18 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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) \u2014 the bounded-context boundary may be in the wrong place, or one context is leaking into the other. This is the behavioural boundary violation a static scan can\u0027t see. You can check this without leaving the row: of the 9 shared commits counted here, the most recent 3 are \u0060e065c0e8\u0060 Add the Donations section and reminder entry point to Settings; \u0060af9946d6\u0060 Add the Donations section and reminder entry point to Settings; \u006078664021\u0060 Add home feed feature flag, home coordinator, empty feed view control\u2026 \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Coordinator/SettingsCoordinatorDelegate.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"732ebdb2b2a4a44cc85fbe6faf888ad1f2e0aef585133331ab95dace40cfa54c"}},{"ruleId":"D35","level":"error","message":{"text":"Boundary-crossing change coupling: TimelineViewModel.swift \u2194 UserContributionsDataController.swift: \u0060WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/TimelineViewModel.swift\u0060 (context WMFComponents) and \u0060WMFData/Sources/WMFData/Data Controllers/Shared/UserContributionsDataController.swift\u0060 (context WMFData) sit in DIFFERENT parts of the tree yet change together 50% of the time (5 of the 10 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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) \u2014 the bounded-context boundary may be in the wrong place, or one context is leaking into the other. This is the behavioural boundary violation a static scan can\u0027t see. You can check this without leaving the row: of the 5 shared commits counted here, the most recent 3 are \u0060b2e32bed\u0060 PR Clean ups; \u00601470f7ca\u0060 Clean up (at that commit the file was still \u0060WMFData/Sources/WMFData/Data Controllers/Activity Tab/UserContributionsDataController.swift\u0060); \u006003c78cd6\u0060 Deep link diff (at that commit the file was still \u0060WMFData/Sources/WMFData/Data Controllers/Activity Tab/UserContributionsDataController.swift\u0060) \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/TimelineViewModel.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"172659e631feda4d6cf3b0db35fe33491ff88ef50ff7d3e76c832ebbdc73009f"}},{"ruleId":"D35","level":"warning","message":{"text":"Change coupling: WMFCommunityFeedView.swift \u2194 WMFHomeViewModel.swift: \u0060WMFComponents/Sources/WMFComponents/Components/Home/WMFCommunityFeedView.swift\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Home/WMFHomeViewModel.swift\u0060 change together 73% of the time (8 of the 11 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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). They sit in the same directory, and in this ecosystem sibling files there normally share one namespace/package \u2014 so a direct reference between them needs no import and this pass cannot see whether one exists. Read the pair before acting: if one file only DECLARES what the other consumes (a constants/types file beside its user), the co-change is definitional and the question is whether the split earns its keep; if they duplicate structure, extract the common part into a shared function or type they both call; if neither holds, the coupling is hidden and worth breaking. You can check this without leaving the row: of the 8 shared commits counted here, the most recent 3 are \u00605321204f\u0060 Allow scrolling to top when tapping the tab button or W button, add a\u2026; \u0060708aac2d\u0060 Hide community card implementation; \u006035333002\u0060 Hide community module implementation \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Home/WMFCommunityFeedView.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"e65a47ccf797aa9d060313e4f0a6f4e932f2c62718e511e0ba956071e14bb075"}},{"ruleId":"D35","level":"warning","message":{"text":"Change coupling: ArticleViewController\u002BArticlePreviewing.swift \u2194 ColumnarCollectionViewController.swift: \u0060Wikipedia/Code/ArticleViewController\u002BArticlePreviewing.swift\u0060 and \u0060Wikipedia/Code/ColumnarCollectionViewController.swift\u0060 change together 69% of the time (9 of the 13 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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). They sit in the same directory, and in this ecosystem sibling files there normally share one namespace/package \u2014 so a direct reference between them needs no import and this pass cannot see whether one exists. Read the pair before acting: if one file only DECLARES what the other consumes (a constants/types file beside its user), the co-change is definitional and the question is whether the split earns its keep; if they duplicate structure, extract the common part into a shared function or type they both call; if neither holds, the coupling is hidden and worth breaking. You can check this without leaving the row: of the 9 shared commits counted here, the most recent 3 are \u0060b842cfd1\u0060 Move text view delegate to tabs coordinator; \u0060aee58be7\u0060 Add link delegate to tabsOverviewCoordinator dor did you know; \u00605ffeb101\u0060 Add sourceRect and sourceView to shareActivityController popover when\u2026 \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleViewController\u002BArticlePreviewing.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"fd01291e05aad62f1ad04dcf2a06562589d4b65654e18ace500172556d4cc1bd"}},{"ruleId":"D35","level":"warning","message":{"text":"Change-coupling hub: InsertLinkViewController.swift \u2192 ArticleViewController.swift, EditLinkViewController.swift, SearchViewController.swift: \u0060Wikipedia/Code/InsertLinkViewController.swift\u0060 changes together with 3 other files \u2014 \u0060Wikipedia/Code/ArticleViewController.swift\u0060, \u0060Wikipedia/Code/EditLinkViewController.swift\u0060, \u0060Wikipedia/Code/SearchViewController.swift\u0060 \u2014 none of which declares a dependency on it: one file is the hub of 3 separate couplings, not 3 unrelated pairs. Read the hub first: if the others each duplicate a part of what it does, the shared concern belongs in ONE unit and extracting it clears every edge at once; if the hub is a registry, dispatcher or barrel that must name each of them, the coupling is structural and the question is whether that list can be discovered instead of enumerated. Fixing the hub is one change; breaking the couplings one pair at a time is 3."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/InsertLinkViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"f38dbbe7c90aeb8cb072e7dc37fdadf046da1f348c5c957b054195b2270283c1"}},{"ruleId":"D35","level":"warning","message":{"text":"Change coupling: ArticleViewController\u002BArticlePreviewing.swift \u2194 ExploreCardViewController.swift: \u0060Wikipedia/Code/ArticleViewController\u002BArticlePreviewing.swift\u0060 and \u0060Wikipedia/Code/ExploreCardViewController.swift\u0060 change together 62% of the time (8 of the 13 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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). They sit in the same directory, and in this ecosystem sibling files there normally share one namespace/package \u2014 so a direct reference between them needs no import and this pass cannot see whether one exists. Read the pair before acting: if one file only DECLARES what the other consumes (a constants/types file beside its user), the co-change is definitional and the question is whether the split earns its keep; if they duplicate structure, extract the common part into a shared function or type they both call; if neither holds, the coupling is hidden and worth breaking. You can check this without leaving the row: of the 8 shared commits counted here, the most recent 3 are \u0060b842cfd1\u0060 Move text view delegate to tabs coordinator; \u0060aee58be7\u0060 Add link delegate to tabsOverviewCoordinator dor did you know; \u00605ffeb101\u0060 Add sourceRect and sourceView to shareActivityController popover when\u2026 \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ArticleViewController\u002BArticlePreviewing.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"b4ddf74448c9035c3f6dffb7259bdabd612142c5fd4a30630ee2adae166048b4"}},{"ruleId":"D35","level":"warning","message":{"text":"Change-coupling hub: ExploreViewController.swift \u2192 InsertLinkViewController.swift, UIViewController\u002BFeatureComponentFactory.swift, WMFDailyGameContentSource.swift, WMFSettingsViewController\u002BExtensions.swift: \u0060Wikipedia/Code/ExploreViewController.swift\u0060 changes together with 4 other files \u2014 \u0060Wikipedia/Code/InsertLinkViewController.swift\u0060, \u0060Wikipedia/Code/UIViewController\u002BFeatureComponentFactory.swift\u0060, \u0060Wikipedia/Code/WMFDailyGameContentSource.swift\u0060, \u0060Wikipedia/Code/WMFSettingsViewController\u002BExtensions.swift\u0060 \u2014 none of which declares a dependency on it: one file is the hub of 4 separate couplings, not 4 unrelated pairs. Read the hub first: if the others each duplicate a part of what it does, the shared concern belongs in ONE unit and extracting it clears every edge at once; if the hub is a registry, dispatcher or barrel that must name each of them, the coupling is structural and the question is whether that list can be discovered instead of enumerated. Fixing the hub is one change; breaking the couplings one pair at a time is 4."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/ExploreViewController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"0346729592c315410ecae8a24439eab3a3396dbc1f0109bffcb301785b5a6f53"}},{"ruleId":"D35","level":"warning","message":{"text":"Change coupling: WMFUserDefaultsKey.swift \u2194 WMFMockDeveloperSettingsDataController.swift: \u0060WMFData/Sources/WMFData/Store/WMFUserDefaultsKey.swift\u0060 and \u0060WMFData/Sources/WMFDataMocks/WMFMockDeveloperSettingsDataController.swift\u0060 change together 60% of the time (21 of the 35 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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). They sit in different directories, but in this ecosystem the namespace is declared in the FILE, not by the folder \u2014 so the two may well share one namespace and reference each other with no import for this pass to see. Read the pair before acting: if one derives from or overrides the other, the dependency is explicit in the type declaration and the co-change is definitional; if one registers itself into the other through a hook or an initialiser, the missing dependency is DELIBERATE and the thing to add is a comment saying so; if they simply belong together, co-locate them; if none of these holds, the coupling is hidden and worth breaking. You can check this without leaving the row: of the 21 shared commits counted here, the most recent 3 are \u0060ad82e504\u0060 Start dev settings; \u006010687bcc\u0060 Combine dev settings; \u0060e9512d60\u0060 Developer settings (to be merged with others), show old yir \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Store/WMFUserDefaultsKey.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"24a414e6ca6253116e614dff423c45bb9d9f7625b66efad135ff92a1fcc2008f"}},{"ruleId":"D35","level":"warning","message":{"text":"Change coupling: WMFSavedAllArticlesViewModel.swift \u2194 WMFAsyncPageRowSaved.swift: \u0060WMFComponents/Sources/WMFComponents/Components/Saved/All Articles/WMFSavedAllArticlesViewModel.swift\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Shared/Page/WMFAsyncPageRowSaved.swift\u0060 change together 57% of the time (12 of the 21 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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). They sit in different directories, but in this ecosystem the namespace is declared in the FILE, not by the folder \u2014 so the two may well share one namespace and reference each other with no import for this pass to see. Read the pair before acting: if one derives from or overrides the other, the dependency is explicit in the type declaration and the co-change is definitional; if one registers itself into the other through a hook or an initialiser, the missing dependency is DELIBERATE and the thing to add is a comment saying so; if they simply belong together, co-locate them; if none of these holds, 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 \u00609ca84168\u0060 Add missing Saved All Articles events; \u006046eccea2\u0060 Add reading list tag tap, remove Saved tag display (at that commit the files were still \u0060WMFComponents/Sources/WMFComponents/Components/Saved/All Articles/WMFAllArticlesViewModel.swift\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Saved/All Articles/WMFAsyncPageRowSaved.swift\u0060); \u0060f64e574d\u0060 Add retry logic for API error (at that commit the files were still \u0060WMFComponents/Sources/WMFComponents/Components/Saved/All Articles/WMFAllArticlesViewModel.swift\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Saved/All Articles/WMFAsyncPageRowSaved.swift\u0060) \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Saved/All Articles/WMFSavedAllArticlesViewModel.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"89b4f437e25aa0ea5e128c60f8411f26b4278cf6449ae54d4ec531670cc53059"}},{"ruleId":"D35","level":"warning","message":{"text":"Change coupling: TimelineViewModel.swift \u2194 WMFActivityTabView.swift: \u0060WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/TimelineViewModel.swift\u0060 and \u0060WMFComponents/Sources/WMFComponents/Components/Activity Tab/WMFActivityTabView.swift\u0060 change together 55% of the time (11 of the 20 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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). They sit in different directories, but in this ecosystem the namespace is declared in the FILE, not by the folder \u2014 so the two may well share one namespace and reference each other with no import for this pass to see. Read the pair before acting: if one derives from or overrides the other, the dependency is explicit in the type declaration and the co-change is definitional; if one registers itself into the other through a hook or an initialiser, the missing dependency is DELIBERATE and the thing to add is a comment saying so; if they simply belong together, co-locate them; if none of these holds, the coupling is hidden and worth breaking. You can check this without leaving the row: of the 11 shared commits counted here, the most recent 3 are \u00601470f7ca\u0060 Clean up; \u006003c78cd6\u0060 Deep link diff; \u00603ce2fc5e\u0060 UserContributions fetch edits \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFComponents/Sources/WMFComponents/Components/Activity Tab/View Models/TimelineViewModel.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"63feaf8af64fca572678e6daaa036fa1693f70ad49ce26d37e0c156468255ff6"}},{"ruleId":"D35","level":"warning","message":{"text":"Change coupling: WMFArticleTabsDataController.swift \u2194 WMFCategoriesDataController.swift: \u0060WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift\u0060 and \u0060WMFData/Sources/WMFData/Data Controllers/Shared/WMFCategoriesDataController.swift\u0060 change together 55% of the time (6 of the 11 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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). They sit in different directories, but in this ecosystem the namespace is declared in the FILE, not by the folder \u2014 so the two may well share one namespace and reference each other with no import for this pass to see. Read the pair before acting: if one derives from or overrides the other, the dependency is explicit in the type declaration and the co-change is definitional; if one registers itself into the other through a hook or an initialiser, the missing dependency is DELIBERATE and the thing to add is a comment saying so; if they simply belong together, co-locate them; if none of these holds, the coupling is hidden and worth breaking. You can check this without leaving the row: of the 6 shared commits counted here, the most recent 3 are \u006085b3ba4a\u0060 Swift 6 (WMFData): replace legacy NSMergePolicy global vars; \u00609a38212a\u0060 Fix iOS 17\u002B deprecations and Sendable warnings; \u0060eda77d8a\u0060 Cleanup WMFProject identifiers \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMFData/Sources/WMFData/Data Controllers/Article Tabs/WMFArticleTabsDataController.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"f803d7491c0b69cae9c3406f27e90d093595a632a43c4eb9d0e35df7312419f8"}},{"ruleId":"D35","level":"warning","message":{"text":"Change coupling: RandomArticleCoordinator.swift \u2194 TabsOverviewCoordinator.swift: \u0060Wikipedia/Code/RandomArticleCoordinator.swift\u0060 and \u0060Wikipedia/Code/TabsOverviewCoordinator.swift\u0060 change together 50% of the time (6 of the 12 commits that touched whichever of the two files changed less often, counting a file under its earlier names as well, and counted over this repository\u0027s 10,000 most recent commits rather than its whole history \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). They sit in the same directory, and in this ecosystem sibling files there normally share one namespace/package \u2014 so a direct reference between them needs no import and this pass cannot see whether one exists. Read the pair before acting: if one file only DECLARES what the other consumes (a constants/types file beside its user), the co-change is definitional and the question is whether the split earns its keep; if they duplicate structure, extract the common part into a shared function or type they both call; if neither holds, the coupling is hidden and worth breaking. You can check this without leaving the row: of the 6 shared commits counted here, the most recent 3 are \u0060152a810e\u0060 Move did you know provider to coordinator; \u0060b842cfd1\u0060 Move text view delegate to tabs coordinator; \u0060f640b632\u0060 Add did you know provider closure call to expore feed, history, artic\u2026 \u2014 run \u0060git show\u0060 on any of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/RandomArticleCoordinator.swift"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"8a61086ed31f67e5ebd6ec2ef877a820099b7b7d133ac23f2e385bd50e0adf2d"}},{"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":"1b213f6eedd4b140d0bc37bdf1496f72811a643f34064f12518b32e9e83bcfc7"}},{"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":"0e17f71490e4d120a48b2b2881ab866c93b272bef2febb673a3e8e42b2c288ab"}},{"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":"eb00976a698a5d68999b7ee6d27206fd374e916853e7ff1ead5eed42386f043f"}},{"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":"90f83b4fa27db32740afe9540c905f3c0499caed87f61049a8a903ecc95b41c3"}},{"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":"0752d0df7434000fcabf1048e2de30a7a1a8b982b3db9a19898c4dec199856b4"}},{"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":"d068c977b62d9a977df1bb6f53e8b00b586c3abee955f91d715f92b8e019d624"}},{"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":"d657599f6f99da1927d3377533dfc0888b34c4d84aa7d5579841fd72d0e39bce"}},{"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":"D44","level":"warning","message":{"text":"End-of-life runtime: Ruby 3.0: .ruby-version declares Ruby 3.0 as this project\u0027s version file, and Ruby 3.0, support ended 2024-04-23. An unsupported runtime receives no security patches, so every vulnerability disclosed in it since 2024-04-23 is present and unfixable without moving off it. This is a migration rather than an upgrade: there is no newer release of a runtime that has ended."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"9a94eb8e3ada0fdf1c1e5606da981d6e4a4b4e00ccb346b0aeb620b5276a8566"}},{"ruleId":"AC1","level":"error","message":{"text":"\u003Cimg\u003E without a text alternative: An image with no alt (and no aria-label/aria-labelledby) is unreadable to assistive tech. Add alt \u2014 alt=\u0022\u0022 if it\u0027s purely decorative."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/assets/about.html"},"region":{"startLine":95}}}],"partialFingerprints":{"codehealthFindingId/v1":"3ea81f3de6bf492034f75f03f3e914631d6a4d40dab854d098bc51bedeaae8d3"}},{"ruleId":"AC1","level":"error","message":{"text":"\u003Cimg\u003E without a text alternative: An image with no alt (and no aria-label/aria-labelledby) is unreadable to assistive tech. Add alt \u2014 alt=\u0022\u0022 if it\u0027s purely decorative."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/assets/about.html"},"region":{"startLine":96}}}],"partialFingerprints":{"codehealthFindingId/v1":"418ef03717e7cb9b1359fb6eb07acb2713953c70ccbb0ed0d5691a3624781262"}},{"ruleId":"AC3","level":"error","message":{"text":"\u003Chtml\u003E without a lang: The page declares no language, so assistive tech can\u0027t pick the right pronunciation. Add lang (e.g. lang=\u0022en\u0022)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFRandomDiceButton.html"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"7fbe3a9554af8e71493d0123f02be9b8be02a0f7acefb7765aaec4fad79e6e58"}},{"ruleId":"AC3","level":"error","message":{"text":"Document without a \u003Ctitle\u003E: A page with no \u003Ctitle\u003E gives no name in the tab, history or screen-reader page list. Add a descriptive \u003Ctitle\u003E in \u003Chead\u003E."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFRandomDiceButton.html"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"c1f63989c02e1096a39df8aa7598a9deb8879abe4fb246a00c9ccb6f4c11539d"}},{"ruleId":"AC3","level":"error","message":{"text":"Viewport restricts zoom: user-scalable=no/0 or a maximum-scale below 2 stops low-vision users zooming to 200%. Remove the zoom restriction from the viewport meta."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFRandomDiceButton.html"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"86c7b9bce41564f78b707ac1a709d9180a33be106496d11d85af55aa28560ff8"}},{"ruleId":"AC3","level":"error","message":{"text":"\u003Chtml\u003E without a lang: The page declares no language, so assistive tech can\u0027t pick the right pronunciation. Add lang (e.g. lang=\u0022en\u0022)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/assets/about.html"},"region":{"startLine":2}}}],"partialFingerprints":{"codehealthFindingId/v1":"48598d9d664d6505c84352909883e45bba0dde9c50d86658ad7d8ec6f19df0f7"}},{"ruleId":"AC3","level":"error","message":{"text":"Document without a \u003Ctitle\u003E: A page with no \u003Ctitle\u003E gives no name in the tab, history or screen-reader page list. Add a descriptive \u003Ctitle\u003E in \u003Chead\u003E."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/assets/about.html"},"region":{"startLine":2}}}],"partialFingerprints":{"codehealthFindingId/v1":"404d4f4f2285ff38f05a884a37bca38912def9c67b811cdd3f582184d045c8a6"}},{"ruleId":"AC3","level":"warning","message":{"text":"Page without a main landmark: No \u003Cmain\u003E (or role=\u0022main\u0022) means no \u0022skip to content\u0022 target and a weaker landmark map. Wrap the primary content in \u003Cmain\u003E."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/assets/about.html"},"region":{"startLine":2}}}],"partialFingerprints":{"codehealthFindingId/v1":"39e9d096a89e81d47c5e56374511974eba8e4884274f915565f88828d5585baf"}},{"ruleId":"AC3","level":"error","message":{"text":"Viewport restricts zoom: user-scalable=no/0 or a maximum-scale below 2 stops low-vision users zooming to 200%. Remove the zoom restriction from the viewport meta."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/assets/about.html"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"10e7104927aa73a4dc8a093c43f890ba00e502856700afa00d361eae3c16efa4"}},{"ruleId":"AC3","level":"warning","message":{"text":"Data table has no header cells: A \u003Ctable\u003E with data cells but no \u003Cth\u003E gives assistive technology no way to associate cells with their headers. Mark the header row/column cells as \u003Cth\u003E (with a scope)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/assets/about.html"},"region":{"startLine":93}}}],"partialFingerprints":{"codehealthFindingId/v1":"ff5786a68d4241f3a4992d69d3de392a1fef0f4f157c7f7340391948077814e5"}},{"ruleId":"AC6","level":"warning","message":{"text":"Animation without a prefers-reduced-motion guard: This stylesheet animates but never checks prefers-reduced-motion, so motion-sensitive users can\u0027t opt out. Wrap motion in @media (prefers-reduced-motion: no-preference)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/WMFRandomDiceButton.html"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"9e0e544d8c09c03b46b5a3b61001bee318932222a4763f6510b8fe20634875bf"}},{"ruleId":"AC7","level":"warning","message":{"text":"Accessibility enforcement below the top rung: No accessibility enforcement found \u2014 no accessibility linting at author time and no automated accessibility check in tests or CI. Add your UI toolkit\u0027s own accessibility assertion to the test suite (Flutter \u0060meetsGuideline\u0060, Espresso \u0060AccessibilityChecks\u0060, XCTest \u0060performAccessibilityAudit\u0060), then gate that test in the pipeline. What was searched, so you can tell an absence from a miss: the 2 markup file(s) this pass actually assessed, the linter configuration checked in beside them, and this repository\u0027s test and CI files \u2014 matched by name against the accessibility checkers this dimension carries. An audit run outside the repository, a hosted scanner, or a check whose name is not one of those, is not seen here."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"d46019b86eff5ddad9db289e6802ac158899e980df54c34f67722442787ead62"}},{"ruleId":"AX8","level":"error","message":{"text":"Production project references a test project: WMFComponents \u2192 WMFDataMocks: \u0060WMFComponents\u0060 (production) references the test project \u0060WMFDataMocks\u0060. Production must never depend on test code \u2014 it pulls a unit-test framework and test fixtures into the shipped product and inverts the only correct direction (tests depend on production, never the reverse). Move any shared helper into a production support library, or invert the reference."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"24a41f48efedfb9eaa1ccf092b11d2c76f78d8243ad839ab5025848bf96ecb18"}},{"ruleId":"DM4","level":"error","message":{"text":"Anemic domain model: InsertMediaSearchResult: \u0060InsertMediaSearchResult\u0060 is a data-only reference entity whose behaviour is DELEGATED to a foreign utility (static methods that take it as their first parameter and hold its logic) \u2014 the anemic domain model. Move the behaviour onto the entity so it enforces its own invariants rather than being driven from outside."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"Wikipedia/Code/InsertMediaSearchResultsCollectionViewController.swift"},"region":{"startLine":55}}}],"partialFingerprints":{"codehealthFindingId/v1":"d6239fca6ca7a20214cae45c0537c3650407e3fb1fc48209a75775148209e7c9"}},{"ruleId":"DM4","level":"error","message":{"text":"Anemic domain model: URLRequest: \u0060URLRequest\u0060 is a data-only reference entity whose behaviour is DELEGATED to a foreign utility (static methods that take it as their first parameter and hold its logic) \u2014 the anemic domain model. Move the behaviour onto the entity so it enforces its own invariants rather than being driven from outside."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"WMF Framework/PermanentlyPersistableURLCache.swift"},"region":{"startLine":704}}}],"partialFingerprints":{"codehealthFindingId/v1":"1f19e4abf301dad83e2417effea3f57d00e4cc3920aed4b5c88a879e4688fe6e"}},{"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":"M3","level":"note","message":{"text":"No src/ separation: Production code isn\u0027t grouped under a src/ folder \u2014 it\u0027s spread across several top-level directories, so there\u0027s no one place that says \u0027this is the product\u0027."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"fdf7f5b24e313364d10170a5c2542959902fe0d26ed70edef3eaa10ec5bcdb1d"}},{"ruleId":"P3","level":"note","message":{"text":"No SAST: No static application security testing detected. For this repository\u0027s stack, add CodeQL\u0027s Swift pack (Swift/Xcode) (or \u0060semgrep --config=auto\u0060, which runs on any language) as a CI step. What was searched, so you can tell an absence from a miss: the 90246 CI workflow file(s) in this repository, and the scanner and linter configuration checked in beside them. A scan that runs outside CI, one configured in your forge\u0027s web UI rather than in a committed file, or a tool whose name is none of those this check carries, is not seen \u2014 if that is your case the row is wrong, and saying so is more useful than adding a second scanner."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"6e54424179c892f03ef2fd003130ac4bd43f39bbf3b1ca0a0143e25acb80ec87"}},{"ruleId":"P6","level":"note","message":{"text":"No changelog: No CHANGELOG/HISTORY/RELEASES file \u2014 what shipped when isn\u0027t easy to reconstruct for support or audit. (Versioning/tagging makes releases traceable, but a changelog records the what.)"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"dda5aa5aed8cbb292c3ef2b733bc138f614293ae6426c85e98bf31ef330d9415"}}],"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-1059","guid":"a2381a08-60f6-9554-a8b8-f3018cfaaca5","name":"Insufficient Technical Documentation","shortDescription":{"text":"Insufficient Technical Documentation"},"helpUri":"https://cwe.mitre.org/data/definitions/1059.html"},{"id":"CWE-134","guid":"f92eb270-a113-5050-a4e8-7173e51af580","name":"CWE-134","shortDescription":{"text":"CWE-134"},"helpUri":"https://cwe.mitre.org/data/definitions/134.html"},{"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-214","guid":"b10ad120-fb22-1351-9348-aa23b453e815","name":"CWE-214","shortDescription":{"text":"CWE-214"},"helpUri":"https://cwe.mitre.org/data/definitions/214.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-319","guid":"7af97476-9f0d-4458-9163-3d2043918a1a","name":"CWE-319","shortDescription":{"text":"CWE-319"},"helpUri":"https://cwe.mitre.org/data/definitions/319.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-457","guid":"b62874fe-6222-8b5b-8ade-9527ad1cbb4a","name":"CWE-457","shortDescription":{"text":"CWE-457"},"helpUri":"https://cwe.mitre.org/data/definitions/457.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-522","guid":"71fb233e-ce6a-ae57-9419-ef8373540b09","name":"CWE-522","shortDescription":{"text":"CWE-522"},"helpUri":"https://cwe.mitre.org/data/definitions/522.html"},{"id":"CWE-532","guid":"1cd8877a-76e8-ce54-b40b-779af23364a0","name":"CWE-532","shortDescription":{"text":"CWE-532"},"helpUri":"https://cwe.mitre.org/data/definitions/532.html"},{"id":"CWE-668","guid":"e2cb99db-6d24-b056-b0d0-885a733ec403","name":"CWE-668","shortDescription":{"text":"CWE-668"},"helpUri":"https://cwe.mitre.org/data/definitions/668.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"},{"id":"CWE-943","guid":"da8ca609-5263-5d50-8f65-8e61b9587003","name":"CWE-943","shortDescription":{"text":"CWE-943"},"helpUri":"https://cwe.mitre.org/data/definitions/943.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":63,"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."]}]}