prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Allow vendor-specific annotations in `meltano.yml`
  Discussed in https://github.com/meltano/meltano/discussions/7053
  
  We should update `meltano.schema.json` to permit an object with arbitrary fields (i.e. `"additionalProperties": true`) within any object in the schema that does not already impose restrictions on the permitted additional properties. That is to say:
  - If the object has `"additionalProperties": true`, then it can have `annotations`, and no changes are required to the schema.
  - If the object has `"additionalProperties": false`, then it can have `annotations` and we must explicitly add it to the properties.
  - If the object has `additionalProperties` set to anything else (e.g. limiting it to strings as `env` does), then annotations are not supported, and no change to the schema is necessary.
  
  So the only places in the schema that need to be updated are where it says `"additionalProperties": false`.
  
  Documentation around what this field is for should be added. It should be made clear that the core Meltano library/CLI does not use this field, but it may be used for Meltano Cloud, or third-party tools.
  
  The documentation should also state that we impose no limitation on how it can be used except for requiring that the top-level of each annotation object may only contain objects as properties, and that we recommend that third-party tools keep their annotations under a sensible key, such as the name of the tool.
  
  Testing should be done by adding annotations liberally to integration tests, and ensuring that they are ignored.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/meltano/core/meltano_file.py`
  Content:
  ```
  1 """Module for working with meltano.yml files."""
  2 from __future__ import annotations
  3 
  4 import copy
  5 from typing import Iterable
  6 
  7 from meltano.core.behavior.canonical import Canonical
  8 from meltano.core.environment import Environment
  9 from meltano.core.plugin import PluginType
  10 from meltano.core.plugin.project_plugin import ProjectPlugin
  11 from meltano.core.schedule import Schedule
  12 from meltano.core.task_sets import TaskSets
  13 
  14 VERSION = 1
  15 
  16 
  17 class MeltanoFile(Canonical):
  18     """Data and loading methods for meltano.yml files."""
  19 
  20     def __init__(
  21         self,
  22         version: int = VERSION,
  23         plugins: dict[str, dict] = None,
  24         schedules: list[dict] = None,
  25         environments: list[dict] = None,
  26         jobs: list[dict] = None,
  27         env: dict[str, str] = None,
  28         **extras,
  29     ):
  30         """Construct a new MeltanoFile object from meltano.yml file.
  31 
  32         Args:
  33             version: The meltano.yml version, currently always 1.
  34             plugins: Plugin configuration for this project.
  35             schedules: Schedule configuration for this project.
  36             environments: Environment configuration for this project.
  37             jobs: Job configuration for this project.
  38             env: Environment variables for this project.
  39             extras: Additional configuration for this project.
  40         """
  41         super().__init__(
  42             # Attributes will be listed in meltano.yml in this order:
  43             version=version,
  44             extras=extras,
  45             plugins=self.load_plugins(plugins or {}),
  46             schedules=self.load_schedules(schedules or []),
  47             environments=self.load_environments(environments or []),
  48             jobs=self.load_job_tasks(jobs or []),
  49             env=env or {},
  50         )
  51 
  52     def load_plugins(self, plugins: dict[str, dict]) -> Canonical:
  53         """Parse the `meltano.yml` file and return it as `ProjectPlugin` instances.
  54 
  55         Args:
  56             plugins: Dictionary of plugin configurations.
  57 
  58         Returns:
  59             New ProjectPlugin instances.
  60         """
  61         plugin_type_plugins = Canonical()
  62 
  63         for ptype in PluginType:
  64             plugin_type_plugins[ptype] = []
  65 
  66         # this will parse the meltano.yml file and create an instance of the
  67         # corresponding `plugin_class` for all the plugins.
  68         for plugin_type, raw_plugins in plugins.items():
  69             if plugin_type == PluginType.MAPPERS:
  70                 for mapper in raw_plugins:
  71                     plugin_type_plugins[PluginType.MAPPERS].append(
  72                         ProjectPlugin(PluginType.MAPPERS, **mapper)
  73                     )
  74                     plugin_type_plugins[PluginType.MAPPERS].extend(
  75                         self.get_plugins_for_mappings(mapper)
  76                     )
  77             else:
  78                 for raw_plugin in raw_plugins:
  79                     plugin = ProjectPlugin(PluginType(plugin_type), **raw_plugin)
  80                     plugin_type_plugins[plugin.type].append(plugin)
  81 
  82         return plugin_type_plugins
  83 
  84     def load_schedules(self, schedules: list[dict]) -> list[Schedule]:
  85         """Parse the meltano.yml file and return it as Schedule instances.
  86 
  87         Args:
  88             schedules: List of schedule configurations.
  89 
  90         Returns:
  91             List of new Schedule instances.
  92         """
  93         return list(map(Schedule.parse, schedules))
  94 
  95     @staticmethod
  96     def load_environments(environments: Iterable[dict]) -> list[Environment]:
  97         """Parse `Environment` objects from python objects.
  98 
  99         Args:
  100             environments: Sequence of environment dictionaries.
  101 
  102         Returns:
  103             A list of `Environment` objects.
  104         """
  105         return [Environment.parse(obj) for obj in environments]
  106 
  107     @staticmethod
  108     def load_job_tasks(jobs: Iterable[dict]) -> list[TaskSets]:
  109         """Parse `TaskSets` objects from python objects.
  110 
  111         Args:
  112             jobs: Sequence of job dictionaries.
  113 
  114         Returns:
  115             A list of `Job` objects.
  116         """
  117         return [TaskSets.parse(obj) for obj in jobs]
  118 
  119     @staticmethod
  120     def get_plugins_for_mappings(mapper_config: dict) -> list[ProjectPlugin]:
  121         """Mapper plugins are a special case. They are not a single plugin, but actually a list of plugins generated from the mapping config defined within the mapper config.
  122 
  123         Args:
  124             mapper_config: The dict representation of a mapper config found in in meltano.yml.
  125 
  126         Returns:
  127             A list of `ProjectPlugin` instances.
  128         """
  129         mapping_plugins: list[ProjectPlugin] = []
  130         for mapping in mapper_config.get("mappings", []):
  131             raw_mapping_plugin = copy.deepcopy(mapper_config)
  132             raw_mapping_plugin["mapping"] = True
  133             raw_mapping_plugin["mapping_name"] = mapping.get("name")
  134             raw_mapping_plugin["config"] = mapping.get("config")
  135             mapping_plugins.append(
  136                 ProjectPlugin(PluginType.MAPPERS, **raw_mapping_plugin)
  137             )
  138         return mapping_plugins
  139
  ```
  --- 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/src/meltano/core/meltano_file.py b/src/meltano/core/meltano_file.py
  --- a/src/meltano/core/meltano_file.py
  +++ b/src/meltano/core/meltano_file.py
  @@ -1,8 +1,9 @@
   """Module for working with meltano.yml files."""
  +
   from __future__ import annotations
   
   import copy
  -from typing import Iterable
  +from typing import Any, Iterable
   
   from meltano.core.behavior.canonical import Canonical
   from meltano.core.environment import Environment
  @@ -25,6 +26,7 @@
           environments: list[dict] = None,
           jobs: list[dict] = None,
           env: dict[str, str] = None,
  +        annotations: dict[str, dict[Any, Any]] | None = None,  # noqa: WPS442
           **extras,
       ):
           """Construct a new MeltanoFile object from meltano.yml file.
  @@ -36,6 +38,7 @@
               environments: Environment configuration for this project.
               jobs: Job configuration for this project.
               env: Environment variables for this project.
  +            annotations: Annotations for external tools/vendors - do not access.
               extras: Additional configuration for this project.
           """
           super().__init__(
  @@ -47,6 +50,7 @@
               environments=self.load_environments(environments or []),
               jobs=self.load_job_tasks(jobs or []),
               env=env or {},
  +            annotations=annotations,
           )
   
       def load_plugins(self, plugins: dict[str, dict]) -> Canonical:
  
verification_info: {"golden_diff": "diff --git a/src/meltano/core/meltano_file.py b/src/meltano/core/meltano_file.py\n--- a/src/meltano/core/meltano_file.py\n+++ b/src/meltano/core/meltano_file.py\n@@ -1,8 +1,9 @@\n \"\"\"Module for working with meltano.yml files.\"\"\"\n+\n from __future__ import annotations\n \n import copy\n-from typing import Iterable\n+from typing import Any, Iterable\n \n from meltano.core.behavior.canonical import Canonical\n from meltano.core.environment import Environment\n@@ -25,6 +26,7 @@\n         environments: list[dict] = None,\n         jobs: list[dict] = None,\n         env: dict[str, str] = None,\n+        annotations: dict[str, dict[Any, Any]] | None = None,  # noqa: WPS442\n         **extras,\n     ):\n         \"\"\"Construct a new MeltanoFile object from meltano.yml file.\n@@ -36,6 +38,7 @@\n             environments: Environment configuration for this project.\n             jobs: Job configuration for this project.\n             env: Environment variables for this project.\n+            annotations: Annotations for external tools/vendors - do not access.\n             extras: Additional configuration for this project.\n         \"\"\"\n         super().__init__(\n@@ -47,6 +50,7 @@\n             environments=self.load_environments(environments or []),\n             jobs=self.load_job_tasks(jobs or []),\n             env=env or {},\n+            annotations=annotations,\n         )\n \n     def load_plugins(self, plugins: dict[str, dict]) -> Canonical:\n", "issue": "Allow vendor-specific annotations in `meltano.yml`\nDiscussed in https://github.com/meltano/meltano/discussions/7053\r\n\r\nWe should update `meltano.schema.json` to permit an object with arbitrary fields (i.e. `\"additionalProperties\": true`) within any object in the schema that does not already impose restrictions on the permitted additional properties. That is to say:\r\n- If the object has `\"additionalProperties\": true`, then it can have `annotations`, and no changes are required to the schema.\r\n- If the object has `\"additionalProperties\": false`, then it can have `annotations` and we must explicitly add it to the properties.\r\n- If the object has `additionalProperties` set to anything else (e.g. limiting it to strings as `env` does), then annotations are not supported, and no change to the schema is necessary.\r\n\r\nSo the only places in the schema that need to be updated are where it says `\"additionalProperties\": false`.\r\n\r\nDocumentation around what this field is for should be added. It should be made clear that the core Meltano library/CLI does not use this field, but it may be used for Meltano Cloud, or third-party tools.\r\n\r\nThe documentation should also state that we impose no limitation on how it can be used except for requiring that the top-level of each annotation object may only contain objects as properties, and that we recommend that third-party tools keep their annotations under a sensible key, such as the name of the tool.\r\n\r\nTesting should be done by adding annotations liberally to integration tests, and ensuring that they are ignored.\n", "before_files": [{"content": "\"\"\"Module for working with meltano.yml files.\"\"\"\nfrom __future__ import annotations\n\nimport copy\nfrom typing import Iterable\n\nfrom meltano.core.behavior.canonical import Canonical\nfrom meltano.core.environment import Environment\nfrom meltano.core.plugin import PluginType\nfrom meltano.core.plugin.project_plugin import ProjectPlugin\nfrom meltano.core.schedule import Schedule\nfrom meltano.core.task_sets import TaskSets\n\nVERSION = 1\n\n\nclass MeltanoFile(Canonical):\n    \"\"\"Data and loading methods for meltano.yml files.\"\"\"\n\n    def __init__(\n        self,\n        version: int = VERSION,\n        plugins: dict[str, dict] = None,\n        schedules: list[dict] = None,\n        environments: list[dict] = None,\n        jobs: list[dict] = None,\n        env: dict[str, str] = None,\n        **extras,\n    ):\n        \"\"\"Construct a new MeltanoFile object from meltano.yml file.\n\n        Args:\n            version: The meltano.yml version, currently always 1.\n            plugins: Plugin configuration for this project.\n            schedules: Schedule configuration for this project.\n            environments: Environment configuration for this project.\n            jobs: Job configuration for this project.\n            env: Environment variables for this project.\n            extras: Additional configuration for this project.\n        \"\"\"\n        super().__init__(\n            # Attributes will be listed in meltano.yml in this order:\n            version=version,\n            extras=extras,\n            plugins=self.load_plugins(plugins or {}),\n            schedules=self.load_schedules(schedules or []),\n            environments=self.load_environments(environments or []),\n            jobs=self.load_job_tasks(jobs or []),\n            env=env or {},\n        )\n\n    def load_plugins(self, plugins: dict[str, dict]) -> Canonical:\n        \"\"\"Parse the `meltano.yml` file and return it as `ProjectPlugin` instances.\n\n        Args:\n            plugins: Dictionary of plugin configurations.\n\n        Returns:\n            New ProjectPlugin instances.\n        \"\"\"\n        plugin_type_plugins = Canonical()\n\n        for ptype in PluginType:\n            plugin_type_plugins[ptype] = []\n\n        # this will parse the meltano.yml file and create an instance of the\n        # corresponding `plugin_class` for all the plugins.\n        for plugin_type, raw_plugins in plugins.items():\n            if plugin_type == PluginType.MAPPERS:\n                for mapper in raw_plugins:\n                    plugin_type_plugins[PluginType.MAPPERS].append(\n                        ProjectPlugin(PluginType.MAPPERS, **mapper)\n                    )\n                    plugin_type_plugins[PluginType.MAPPERS].extend(\n                        self.get_plugins_for_mappings(mapper)\n                    )\n            else:\n                for raw_plugin in raw_plugins:\n                    plugin = ProjectPlugin(PluginType(plugin_type), **raw_plugin)\n                    plugin_type_plugins[plugin.type].append(plugin)\n\n        return plugin_type_plugins\n\n    def load_schedules(self, schedules: list[dict]) -> list[Schedule]:\n        \"\"\"Parse the meltano.yml file and return it as Schedule instances.\n\n        Args:\n            schedules: List of schedule configurations.\n\n        Returns:\n            List of new Schedule instances.\n        \"\"\"\n        return list(map(Schedule.parse, schedules))\n\n    @staticmethod\n    def load_environments(environments: Iterable[dict]) -> list[Environment]:\n        \"\"\"Parse `Environment` objects from python objects.\n\n        Args:\n            environments: Sequence of environment dictionaries.\n\n        Returns:\n            A list of `Environment` objects.\n        \"\"\"\n        return [Environment.parse(obj) for obj in environments]\n\n    @staticmethod\n    def load_job_tasks(jobs: Iterable[dict]) -> list[TaskSets]:\n        \"\"\"Parse `TaskSets` objects from python objects.\n\n        Args:\n            jobs: Sequence of job dictionaries.\n\n        Returns:\n            A list of `Job` objects.\n        \"\"\"\n        return [TaskSets.parse(obj) for obj in jobs]\n\n    @staticmethod\n    def get_plugins_for_mappings(mapper_config: dict) -> list[ProjectPlugin]:\n        \"\"\"Mapper plugins are a special case. They are not a single plugin, but actually a list of plugins generated from the mapping config defined within the mapper config.\n\n        Args:\n            mapper_config: The dict representation of a mapper config found in in meltano.yml.\n\n        Returns:\n            A list of `ProjectPlugin` instances.\n        \"\"\"\n        mapping_plugins: list[ProjectPlugin] = []\n        for mapping in mapper_config.get(\"mappings\", []):\n            raw_mapping_plugin = copy.deepcopy(mapper_config)\n            raw_mapping_plugin[\"mapping\"] = True\n            raw_mapping_plugin[\"mapping_name\"] = mapping.get(\"name\")\n            raw_mapping_plugin[\"config\"] = mapping.get(\"config\")\n            mapping_plugins.append(\n                ProjectPlugin(PluginType.MAPPERS, **raw_mapping_plugin)\n            )\n        return mapping_plugins\n", "path": "src/meltano/core/meltano_file.py"}], "after_files": [{"content": "\"\"\"Module for working with meltano.yml files.\"\"\"\n\nfrom __future__ import annotations\n\nimport copy\nfrom typing import Any, Iterable\n\nfrom meltano.core.behavior.canonical import Canonical\nfrom meltano.core.environment import Environment\nfrom meltano.core.plugin import PluginType\nfrom meltano.core.plugin.project_plugin import ProjectPlugin\nfrom meltano.core.schedule import Schedule\nfrom meltano.core.task_sets import TaskSets\n\nVERSION = 1\n\n\nclass MeltanoFile(Canonical):\n    \"\"\"Data and loading methods for meltano.yml files.\"\"\"\n\n    def __init__(\n        self,\n        version: int = VERSION,\n        plugins: dict[str, dict] = None,\n        schedules: list[dict] = None,\n        environments: list[dict] = None,\n        jobs: list[dict] = None,\n        env: dict[str, str] = None,\n        annotations: dict[str, dict[Any, Any]] | None = None,  # noqa: WPS442\n        **extras,\n    ):\n        \"\"\"Construct a new MeltanoFile object from meltano.yml file.\n\n        Args:\n            version: The meltano.yml version, currently always 1.\n            plugins: Plugin configuration for this project.\n            schedules: Schedule configuration for this project.\n            environments: Environment configuration for this project.\n            jobs: Job configuration for this project.\n            env: Environment variables for this project.\n            annotations: Annotations for external tools/vendors - do not access.\n            extras: Additional configuration for this project.\n        \"\"\"\n        super().__init__(\n            # Attributes will be listed in meltano.yml in this order:\n            version=version,\n            extras=extras,\n            plugins=self.load_plugins(plugins or {}),\n            schedules=self.load_schedules(schedules or []),\n            environments=self.load_environments(environments or []),\n            jobs=self.load_job_tasks(jobs or []),\n            env=env or {},\n            annotations=annotations,\n        )\n\n    def load_plugins(self, plugins: dict[str, dict]) -> Canonical:\n        \"\"\"Parse the `meltano.yml` file and return it as `ProjectPlugin` instances.\n\n        Args:\n            plugins: Dictionary of plugin configurations.\n\n        Returns:\n            New ProjectPlugin instances.\n        \"\"\"\n        plugin_type_plugins = Canonical()\n\n        for ptype in PluginType:\n            plugin_type_plugins[ptype] = []\n\n        # this will parse the meltano.yml file and create an instance of the\n        # corresponding `plugin_class` for all the plugins.\n        for plugin_type, raw_plugins in plugins.items():\n            if plugin_type == PluginType.MAPPERS:\n                for mapper in raw_plugins:\n                    plugin_type_plugins[PluginType.MAPPERS].append(\n                        ProjectPlugin(PluginType.MAPPERS, **mapper)\n                    )\n                    plugin_type_plugins[PluginType.MAPPERS].extend(\n                        self.get_plugins_for_mappings(mapper)\n                    )\n            else:\n                for raw_plugin in raw_plugins:\n                    plugin = ProjectPlugin(PluginType(plugin_type), **raw_plugin)\n                    plugin_type_plugins[plugin.type].append(plugin)\n\n        return plugin_type_plugins\n\n    def load_schedules(self, schedules: list[dict]) -> list[Schedule]:\n        \"\"\"Parse the meltano.yml file and return it as Schedule instances.\n\n        Args:\n            schedules: List of schedule configurations.\n\n        Returns:\n            List of new Schedule instances.\n        \"\"\"\n        return list(map(Schedule.parse, schedules))\n\n    @staticmethod\n    def load_environments(environments: Iterable[dict]) -> list[Environment]:\n        \"\"\"Parse `Environment` objects from python objects.\n\n        Args:\n            environments: Sequence of environment dictionaries.\n\n        Returns:\n            A list of `Environment` objects.\n        \"\"\"\n        return [Environment.parse(obj) for obj in environments]\n\n    @staticmethod\n    def load_job_tasks(jobs: Iterable[dict]) -> list[TaskSets]:\n        \"\"\"Parse `TaskSets` objects from python objects.\n\n        Args:\n            jobs: Sequence of job dictionaries.\n\n        Returns:\n            A list of `Job` objects.\n        \"\"\"\n        return [TaskSets.parse(obj) for obj in jobs]\n\n    @staticmethod\n    def get_plugins_for_mappings(mapper_config: dict) -> list[ProjectPlugin]:\n        \"\"\"Mapper plugins are a special case. They are not a single plugin, but actually a list of plugins generated from the mapping config defined within the mapper config.\n\n        Args:\n            mapper_config: The dict representation of a mapper config found in in meltano.yml.\n\n        Returns:\n            A list of `ProjectPlugin` instances.\n        \"\"\"\n        mapping_plugins: list[ProjectPlugin] = []\n        for mapping in mapper_config.get(\"mappings\", []):\n            raw_mapping_plugin = copy.deepcopy(mapper_config)\n            raw_mapping_plugin[\"mapping\"] = True\n            raw_mapping_plugin[\"mapping_name\"] = mapping.get(\"name\")\n            raw_mapping_plugin[\"config\"] = mapping.get(\"config\")\n            mapping_plugins.append(\n                ProjectPlugin(PluginType.MAPPERS, **raw_mapping_plugin)\n            )\n        return mapping_plugins\n", "path": "src/meltano/core/meltano_file.py"}]}