prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Change needsdiagnosis model to consider moved milestone as `needsdiagnosis = True`
  We have observed that needsdiagnosis model classifies certain issues that potentially need diagnosis as `needsdiagnosis = False`. While this is expected, I think it might be getting worse, as the issues data is unbalanced and has much more data points for `needsdiagnosis = False`. We've started a discussion in https://github.com/mozilla/webcompat-team-okrs/issues/256 
  
  It's worth mentioning that in the [recent sample of 22 issues](https://docs.google.com/spreadsheets/d/1F9vcSpLQ_hNBeZinsytGXlfXpJLW6vh7C0BJYtd9hIY/edit?pli=1#gid=1640243023) most of the issues that looked like false negatives didn't end up needing diagnosis (not reproducible,  out of the scope of the project, etc.), so they're true negatives (prediction was correct for 21 of them). We'll continue tracking them to get a more representative sample.
  
  As an example, issues that looked like they need diagnosis, but in the end, they didn't (prediction was correct):
  https://github.com/webcompat/web-bugs/issues/100746
  https://github.com/webcompat/web-bugs/issues/100676
  https://github.com/webcompat/web-bugs/issues/100687
  
  Issues that are false negatives (prediction was incorrect): 
  https://github.com/webcompat/web-bugs/issues/100495
  https://github.com/webcompat/web-bugs/issues/100645
  
  I was thinking of including an additional set of issues that will contribute to `needsdiagnosis = True` pool. We have recently added a `moved` [milestone](https://github.com/webcompat/web-bugs/issues?q=is%3Aissue+milestone%3Amoved+is%3Aclosed). These issues often don't need diagnosis and are moved to bugzilla or elsewhere, but their content should be contributed to `needsdiagnosis = True`  rather than false. 
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `bugbug/models/needsdiagnosis.py`
  Content:
  ```
  1 # -*- coding: utf-8 -*-
  2 # This Source Code Form is subject to the terms of the Mozilla Public
  3 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4 # You can obtain one at http://mozilla.org/MPL/2.0/.
  5 
  6 import logging
  7 
  8 import xgboost
  9 from sklearn.compose import ColumnTransformer
  10 from sklearn.pipeline import Pipeline
  11 
  12 from bugbug import feature_cleanup, issue_features, utils
  13 from bugbug.model import IssueModel
  14 
  15 logger = logging.getLogger(__name__)
  16 
  17 
  18 class NeedsDiagnosisModel(IssueModel):
  19     def __init__(self, lemmatization=False):
  20         IssueModel.__init__(
  21             self, owner="webcompat", repo="web-bugs", lemmatization=lemmatization
  22         )
  23 
  24         self.calculate_importance = False
  25 
  26         feature_extractors = []
  27 
  28         cleanup_functions = [
  29             feature_cleanup.fileref(),
  30             feature_cleanup.url(),
  31             feature_cleanup.synonyms(),
  32         ]
  33 
  34         self.extraction_pipeline = Pipeline(
  35             [
  36                 (
  37                     "issue_extractor",
  38                     issue_features.IssueExtractor(
  39                         feature_extractors, cleanup_functions, rollback=True
  40                     ),
  41                 ),
  42                 (
  43                     "union",
  44                     ColumnTransformer(
  45                         [
  46                             ("title", self.text_vectorizer(min_df=0.0001), "title"),
  47                             (
  48                                 "first_comment",
  49                                 self.text_vectorizer(min_df=0.0001),
  50                                 "first_comment",
  51                             ),
  52                         ]
  53                     ),
  54                 ),
  55             ]
  56         )
  57 
  58         self.clf = xgboost.XGBClassifier(n_jobs=utils.get_physical_cpu_count())
  59         self.clf.set_params(predictor="cpu_predictor")
  60 
  61     def get_labels(self):
  62         classes = {}
  63 
  64         for issue in self.github.get_issues():
  65             # Skip issues with empty title or body
  66             if issue["title"] is None or issue["body"] is None:
  67                 continue
  68 
  69             # Skip issues that are not moderated yet as they don't have a meaningful title or body
  70             if issue["title"] == "In the moderation queue.":
  71                 continue
  72 
  73             for event in issue["events"]:
  74                 if (
  75                     event["event"] == "milestoned"
  76                     and event["milestone"]["title"] == "needsdiagnosis"
  77                 ):
  78                     classes[issue["number"]] = 0
  79 
  80             if issue["number"] not in classes:
  81                 classes[issue["number"]] = 1
  82 
  83         logger.info(
  84             f"{sum(1 for label in classes.values() if label == 1)} issues have not been moved to needsdiagnosis"
  85         )
  86         logger.info(
  87             f"{sum(1 for label in classes.values() if label == 0)} issues have been moved to needsdiagnosis"
  88         )
  89 
  90         return classes, [0, 1]
  91 
  92     def get_feature_names(self):
  93         return self.extraction_pipeline.named_steps["union"].get_feature_names()
  94
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/bugbug/models/needsdiagnosis.py b/bugbug/models/needsdiagnosis.py
  --- a/bugbug/models/needsdiagnosis.py
  +++ b/bugbug/models/needsdiagnosis.py
  @@ -71,9 +71,9 @@
                   continue
   
               for event in issue["events"]:
  -                if (
  -                    event["event"] == "milestoned"
  -                    and event["milestone"]["title"] == "needsdiagnosis"
  +                if event["event"] == "milestoned" and (
  +                    event["milestone"]["title"] == "needsdiagnosis"
  +                    or event["milestone"]["title"] == "moved"
                   ):
                       classes[issue["number"]] = 0
  
verification_info: {"golden_diff": "diff --git a/bugbug/models/needsdiagnosis.py b/bugbug/models/needsdiagnosis.py\n--- a/bugbug/models/needsdiagnosis.py\n+++ b/bugbug/models/needsdiagnosis.py\n@@ -71,9 +71,9 @@\n                 continue\n \n             for event in issue[\"events\"]:\n-                if (\n-                    event[\"event\"] == \"milestoned\"\n-                    and event[\"milestone\"][\"title\"] == \"needsdiagnosis\"\n+                if event[\"event\"] == \"milestoned\" and (\n+                    event[\"milestone\"][\"title\"] == \"needsdiagnosis\"\n+                    or event[\"milestone\"][\"title\"] == \"moved\"\n                 ):\n                     classes[issue[\"number\"]] = 0\n", "issue": "Change needsdiagnosis model to consider moved milestone as `needsdiagnosis = True`\nWe have observed that needsdiagnosis model classifies certain issues that potentially need diagnosis as `needsdiagnosis = False`. While this is expected, I think it might be getting worse, as the issues data is unbalanced and has much more data points for `needsdiagnosis = False`. We've started a discussion in https://github.com/mozilla/webcompat-team-okrs/issues/256 \r\n\r\nIt's worth mentioning that in the [recent sample of 22 issues](https://docs.google.com/spreadsheets/d/1F9vcSpLQ_hNBeZinsytGXlfXpJLW6vh7C0BJYtd9hIY/edit?pli=1#gid=1640243023) most of the issues that looked like false negatives didn't end up needing diagnosis (not reproducible,  out of the scope of the project, etc.), so they're true negatives (prediction was correct for 21 of them). We'll continue tracking them to get a more representative sample.\r\n\r\nAs an example, issues that looked like they need diagnosis, but in the end, they didn't (prediction was correct):\r\nhttps://github.com/webcompat/web-bugs/issues/100746\r\nhttps://github.com/webcompat/web-bugs/issues/100676\r\nhttps://github.com/webcompat/web-bugs/issues/100687\r\n\r\nIssues that are false negatives (prediction was incorrect): \r\nhttps://github.com/webcompat/web-bugs/issues/100495\r\nhttps://github.com/webcompat/web-bugs/issues/100645\r\n\r\nI was thinking of including an additional set of issues that will contribute to `needsdiagnosis = True` pool. We have recently added a `moved` [milestone](https://github.com/webcompat/web-bugs/issues?q=is%3Aissue+milestone%3Amoved+is%3Aclosed). These issues often don't need diagnosis and are moved to bugzilla or elsewhere, but their content should be contributed to `needsdiagnosis = True`  rather than false. \r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this file,\n# You can obtain one at http://mozilla.org/MPL/2.0/.\n\nimport logging\n\nimport xgboost\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.pipeline import Pipeline\n\nfrom bugbug import feature_cleanup, issue_features, utils\nfrom bugbug.model import IssueModel\n\nlogger = logging.getLogger(__name__)\n\n\nclass NeedsDiagnosisModel(IssueModel):\n    def __init__(self, lemmatization=False):\n        IssueModel.__init__(\n            self, owner=\"webcompat\", repo=\"web-bugs\", lemmatization=lemmatization\n        )\n\n        self.calculate_importance = False\n\n        feature_extractors = []\n\n        cleanup_functions = [\n            feature_cleanup.fileref(),\n            feature_cleanup.url(),\n            feature_cleanup.synonyms(),\n        ]\n\n        self.extraction_pipeline = Pipeline(\n            [\n                (\n                    \"issue_extractor\",\n                    issue_features.IssueExtractor(\n                        feature_extractors, cleanup_functions, rollback=True\n                    ),\n                ),\n                (\n                    \"union\",\n                    ColumnTransformer(\n                        [\n                            (\"title\", self.text_vectorizer(min_df=0.0001), \"title\"),\n                            (\n                                \"first_comment\",\n                                self.text_vectorizer(min_df=0.0001),\n                                \"first_comment\",\n                            ),\n                        ]\n                    ),\n                ),\n            ]\n        )\n\n        self.clf = xgboost.XGBClassifier(n_jobs=utils.get_physical_cpu_count())\n        self.clf.set_params(predictor=\"cpu_predictor\")\n\n    def get_labels(self):\n        classes = {}\n\n        for issue in self.github.get_issues():\n            # Skip issues with empty title or body\n            if issue[\"title\"] is None or issue[\"body\"] is None:\n                continue\n\n            # Skip issues that are not moderated yet as they don't have a meaningful title or body\n            if issue[\"title\"] == \"In the moderation queue.\":\n                continue\n\n            for event in issue[\"events\"]:\n                if (\n                    event[\"event\"] == \"milestoned\"\n                    and event[\"milestone\"][\"title\"] == \"needsdiagnosis\"\n                ):\n                    classes[issue[\"number\"]] = 0\n\n            if issue[\"number\"] not in classes:\n                classes[issue[\"number\"]] = 1\n\n        logger.info(\n            f\"{sum(1 for label in classes.values() if label == 1)} issues have not been moved to needsdiagnosis\"\n        )\n        logger.info(\n            f\"{sum(1 for label in classes.values() if label == 0)} issues have been moved to needsdiagnosis\"\n        )\n\n        return classes, [0, 1]\n\n    def get_feature_names(self):\n        return self.extraction_pipeline.named_steps[\"union\"].get_feature_names()\n", "path": "bugbug/models/needsdiagnosis.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this file,\n# You can obtain one at http://mozilla.org/MPL/2.0/.\n\nimport logging\n\nimport xgboost\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.pipeline import Pipeline\n\nfrom bugbug import feature_cleanup, issue_features, utils\nfrom bugbug.model import IssueModel\n\nlogger = logging.getLogger(__name__)\n\n\nclass NeedsDiagnosisModel(IssueModel):\n    def __init__(self, lemmatization=False):\n        IssueModel.__init__(\n            self, owner=\"webcompat\", repo=\"web-bugs\", lemmatization=lemmatization\n        )\n\n        self.calculate_importance = False\n\n        feature_extractors = []\n\n        cleanup_functions = [\n            feature_cleanup.fileref(),\n            feature_cleanup.url(),\n            feature_cleanup.synonyms(),\n        ]\n\n        self.extraction_pipeline = Pipeline(\n            [\n                (\n                    \"issue_extractor\",\n                    issue_features.IssueExtractor(\n                        feature_extractors, cleanup_functions, rollback=True\n                    ),\n                ),\n                (\n                    \"union\",\n                    ColumnTransformer(\n                        [\n                            (\"title\", self.text_vectorizer(min_df=0.0001), \"title\"),\n                            (\n                                \"first_comment\",\n                                self.text_vectorizer(min_df=0.0001),\n                                \"first_comment\",\n                            ),\n                        ]\n                    ),\n                ),\n            ]\n        )\n\n        self.clf = xgboost.XGBClassifier(n_jobs=utils.get_physical_cpu_count())\n        self.clf.set_params(predictor=\"cpu_predictor\")\n\n    def get_labels(self):\n        classes = {}\n\n        for issue in self.github.get_issues():\n            # Skip issues with empty title or body\n            if issue[\"title\"] is None or issue[\"body\"] is None:\n                continue\n\n            # Skip issues that are not moderated yet as they don't have a meaningful title or body\n            if issue[\"title\"] == \"In the moderation queue.\":\n                continue\n\n            for event in issue[\"events\"]:\n                if event[\"event\"] == \"milestoned\" and (\n                    event[\"milestone\"][\"title\"] == \"needsdiagnosis\"\n                    or event[\"milestone\"][\"title\"] == \"moved\"\n                ):\n                    classes[issue[\"number\"]] = 0\n\n            if issue[\"number\"] not in classes:\n                classes[issue[\"number\"]] = 1\n\n        logger.info(\n            f\"{sum(1 for label in classes.values() if label == 1)} issues have not been moved to needsdiagnosis\"\n        )\n        logger.info(\n            f\"{sum(1 for label in classes.values() if label == 0)} issues have been moved to needsdiagnosis\"\n        )\n\n        return classes, [0, 1]\n\n    def get_feature_names(self):\n        return self.extraction_pipeline.named_steps[\"union\"].get_feature_names()\n", "path": "bugbug/models/needsdiagnosis.py"}]}