We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ak.fields (v2) passes a RecordArray's internal fields by reference
Okay, so I hadn't noticed that Awkward v2's fields are passed by reference, which exposes them to the danger that someone might modify them downstream:

v1:

```python
>>> array = awkward.Array([{"x": 1, "y": 1.1}])
>>> fields = awkward.fields(array)
>>> array
<Array [{x: 1, y: 1.1}] type='1 * {"x": int64, "y": float64}'>
>>> fields
['x', 'y']
>>> fields[0] = "XXX"
>>> fields
['XXX', 'y']
>>> array
<Array [{x: 1, y: 1.1}] type='1 * {"x": int64, "y": float64}'>
```

v2:

```python
>>> array = awkward._v2.Array([{"x": 1, "y": 1.1}])
>>> fields = awkward._v2.fields(array)
>>> array
<Array [{x: 1, y: 1.1}] type='1 * {x: int64, y: float64}'>
>>> fields
['x', 'y']
>>> fields[0] = "XXX"
>>> fields
['XXX', 'y']
>>> array
<Array [{XXX: 1, y: 1.1}] type='1 * {XXX: int64, y: float64}'>
```

It could be fixed [here, in Awkward](https://github.com/scikit-hep/awkward/blob/352b0dead74846ad2a56d385be4694ec87072a08/src/awkward/_v2/contents/recordarray.py#L162), or maybe [here](https://github.com/scikit-hep/awkward/blob/352b0dead74846ad2a56d385be4694ec87072a08/src/awkward/_v2/operations/ak_fields.py#L30) (to only suffer the list-copy when handing it off to a user, so that internal uses can still be by reference).

I'll use this comment to open an issue in Awkward. Once `awkward.fields` is guarded, your `.copy()` can be removed, but it can also not be removed with no consequences but a little performance.

_Originally posted by @jpivarski in https://github.com/scikit-hep/vector/pull/226#discussion_r958660705_

--- 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/awkward/_v2/operations/ak_fields.py`
Content:
```
1 # BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE
2 
3 import awkward as ak
4 
5 np = ak.nplike.NumpyMetadata.instance()
6 
7 
8 def fields(array):
9     """
10     Extracts record fields or tuple slot numbers from `array` (many types
11     supported, including all Awkward Arrays and Records).
12 
13     If the array contains nested records, only the outermost record is
14     queried. If it contains tuples instead of records, this function outputs
15     string representations of integers, such as `"0"`, `"1"`, `"2"`, etc.
16     The records or tuples may be within multiple layers of nested lists.
17 
18     If the array contains neither tuples nor records, this returns an empty
19     list.
20     """
21     with ak._v2._util.OperationErrorContext(
22         "ak._v2.fields",
23         dict(array=array),
24     ):
25         return _impl(array)
26 
27 
28 def _impl(array):
29     layout = ak._v2.operations.to_layout(array, allow_record=True, allow_other=False)
30     return layout.fields
31
```

Path: `src/awkward/_v2/operations/ak_parameters.py`
Content:
```
1 # BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE
2 
3 import awkward as ak
4 
5 np = ak.nplike.NumpyMetadata.instance()
6 
7 
8 def parameters(array):
9     """
10     Extracts parameters from the outermost array node of `array` (many types
11     supported, including all Awkward Arrays and Records).
12 
13     Parameters are a dict from str to JSON-like objects, usually strings.
14     Every #ak.layout.Content node has a different set of parameters. Some
15     key names are special, such as `"__record__"` and `"__array__"` that name
16     particular records and arrays as capable of supporting special behaviors.
17 
18     See #ak.Array and #ak.behavior for a more complete description of
19     behaviors.
20     """
21     with ak._v2._util.OperationErrorContext(
22         "ak._v2.parameters",
23         dict(array=array),
24     ):
25         return _impl(array)
26 
27 
28 def _impl(array):
29     if isinstance(array, (ak._v2.highlevel.Array, ak._v2.highlevel.Record)):
30         return array.layout.parameters
31 
32     elif isinstance(
33         array,
34         (ak._v2.contents.Content, ak._v2.record.Record),
35     ):
36         return array.parameters
37 
38     elif isinstance(array, ak._v2.highlevel.ArrayBuilder):
39         return array.snapshot().layout.parameters
40 
41     elif isinstance(array, ak.layout.ArrayBuilder):
42         return array.snapshot().parameters
43 
44     else:
45         return {}
46
```
--- 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()

```

diff --git a/src/awkward/_v2/operations/ak_fields.py b/src/awkward/_v2/operations/ak_fields.py
--- a/src/awkward/_v2/operations/ak_fields.py
+++ b/src/awkward/_v2/operations/ak_fields.py
@@ -27,4 +27,4 @@
 
 def _impl(array):
     layout = ak._v2.operations.to_layout(array, allow_record=True, allow_other=False)
-    return layout.fields
+    return layout.fields.copy()
diff --git a/src/awkward/_v2/operations/ak_parameters.py b/src/awkward/_v2/operations/ak_parameters.py
--- a/src/awkward/_v2/operations/ak_parameters.py
+++ b/src/awkward/_v2/operations/ak_parameters.py
@@ -1,5 +1,8 @@
 # BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE
 
+import copy
+import numbers
+
 import awkward as ak
 
 np = ak.nplike.NumpyMetadata.instance()
@@ -27,13 +30,13 @@
 
 def _impl(array):
     if isinstance(array, (ak._v2.highlevel.Array, ak._v2.highlevel.Record)):
-        return array.layout.parameters
+        return _copy(array.layout.parameters)
 
     elif isinstance(
         array,
         (ak._v2.contents.Content, ak._v2.record.Record),
     ):
-        return array.parameters
+        return _copy(array.parameters)
 
     elif isinstance(array, ak._v2.highlevel.ArrayBuilder):
         return array.snapshot().layout.parameters
@@ -43,3 +46,10 @@
 
     else:
         return {}
+
+
+def _copy(what):
+    if all(isinstance(x, (str, numbers.Real)) for x in what.values()):
+        return what.copy()
+    else:
+        return copy.deepcopy(what)

{"golden_diff": "diff --git a/src/awkward/_v2/operations/ak_fields.py b/src/awkward/_v2/operations/ak_fields.py\n--- a/src/awkward/_v2/operations/ak_fields.py\n+++ b/src/awkward/_v2/operations/ak_fields.py\n@@ -27,4 +27,4 @@\n \n def _impl(array):\n     layout = ak._v2.operations.to_layout(array, allow_record=True, allow_other=False)\n-    return layout.fields\n+    return layout.fields.copy()\ndiff --git a/src/awkward/_v2/operations/ak_parameters.py b/src/awkward/_v2/operations/ak_parameters.py\n--- a/src/awkward/_v2/operations/ak_parameters.py\n+++ b/src/awkward/_v2/operations/ak_parameters.py\n@@ -1,5 +1,8 @@\n # BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE\n \n+import copy\n+import numbers\n+\n import awkward as ak\n \n np = ak.nplike.NumpyMetadata.instance()\n@@ -27,13 +30,13 @@\n \n def _impl(array):\n     if isinstance(array, (ak._v2.highlevel.Array, ak._v2.highlevel.Record)):\n-        return array.layout.parameters\n+        return _copy(array.layout.parameters)\n \n     elif isinstance(\n         array,\n         (ak._v2.contents.Content, ak._v2.record.Record),\n     ):\n-        return array.parameters\n+        return _copy(array.parameters)\n \n     elif isinstance(array, ak._v2.highlevel.ArrayBuilder):\n         return array.snapshot().layout.parameters\n@@ -43,3 +46,10 @@\n \n     else:\n         return {}\n+\n+\n+def _copy(what):\n+    if all(isinstance(x, (str, numbers.Real)) for x in what.values()):\n+        return what.copy()\n+    else:\n+        return copy.deepcopy(what)\n", "issue": "ak.fields (v2) passes a RecordArray's internal fields by reference\nOkay, so I hadn't noticed that Awkward v2's fields are passed by reference, which exposes them to the danger that someone might modify them downstream:\r\n\r\nv1:\r\n\r\n```python\r\n>>> array = awkward.Array([{\"x\": 1, \"y\": 1.1}])\r\n>>> fields = awkward.fields(array)\r\n>>> array\r\n<Array [{x: 1, y: 1.1}] type='1 * {\"x\": int64, \"y\": float64}'>\r\n>>> fields\r\n['x', 'y']\r\n>>> fields[0] = \"XXX\"\r\n>>> fields\r\n['XXX', 'y']\r\n>>> array\r\n<Array [{x: 1, y: 1.1}] type='1 * {\"x\": int64, \"y\": float64}'>\r\n```\r\n\r\nv2:\r\n\r\n```python\r\n>>> array = awkward._v2.Array([{\"x\": 1, \"y\": 1.1}])\r\n>>> fields = awkward._v2.fields(array)\r\n>>> array\r\n<Array [{x: 1, y: 1.1}] type='1 * {x: int64, y: float64}'>\r\n>>> fields\r\n['x', 'y']\r\n>>> fields[0] = \"XXX\"\r\n>>> fields\r\n['XXX', 'y']\r\n>>> array\r\n<Array [{XXX: 1, y: 1.1}] type='1 * {XXX: int64, y: float64}'>\r\n```\r\n\r\nIt could be fixed [here, in Awkward](https://github.com/scikit-hep/awkward/blob/352b0dead74846ad2a56d385be4694ec87072a08/src/awkward/_v2/contents/recordarray.py#L162), or maybe [here](https://github.com/scikit-hep/awkward/blob/352b0dead74846ad2a56d385be4694ec87072a08/src/awkward/_v2/operations/ak_fields.py#L30) (to only suffer the list-copy when handing it off to a user, so that internal uses can still be by reference).\r\n\r\nI'll use this comment to open an issue in Awkward. Once `awkward.fields` is guarded, your `.copy()` can be removed, but it can also not be removed with no consequences but a little performance.\r\n\r\n_Originally posted by @jpivarski in https://github.com/scikit-hep/vector/pull/226#discussion_r958660705_\n", "before_files": [{"content": "# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE\n\nimport awkward as ak\n\nnp = ak.nplike.NumpyMetadata.instance()\n\n\ndef fields(array):\n    \"\"\"\n    Extracts record fields or tuple slot numbers from `array` (many types\n    supported, including all Awkward Arrays and Records).\n\n    If the array contains nested records, only the outermost record is\n    queried. If it contains tuples instead of records, this function outputs\n    string representations of integers, such as `\"0\"`, `\"1\"`, `\"2\"`, etc.\n    The records or tuples may be within multiple layers of nested lists.\n\n    If the array contains neither tuples nor records, this returns an empty\n    list.\n    \"\"\"\n    with ak._v2._util.OperationErrorContext(\n        \"ak._v2.fields\",\n        dict(array=array),\n    ):\n        return _impl(array)\n\n\ndef _impl(array):\n    layout = ak._v2.operations.to_layout(array, allow_record=True, allow_other=False)\n    return layout.fields\n", "path": "src/awkward/_v2/operations/ak_fields.py"}, {"content": "# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE\n\nimport awkward as ak\n\nnp = ak.nplike.NumpyMetadata.instance()\n\n\ndef parameters(array):\n    \"\"\"\n    Extracts parameters from the outermost array node of `array` (many types\n    supported, including all Awkward Arrays and Records).\n\n    Parameters are a dict from str to JSON-like objects, usually strings.\n    Every #ak.layout.Content node has a different set of parameters. Some\n    key names are special, such as `\"__record__\"` and `\"__array__\"` that name\n    particular records and arrays as capable of supporting special behaviors.\n\n    See #ak.Array and #ak.behavior for a more complete description of\n    behaviors.\n    \"\"\"\n    with ak._v2._util.OperationErrorContext(\n        \"ak._v2.parameters\",\n        dict(array=array),\n    ):\n        return _impl(array)\n\n\ndef _impl(array):\n    if isinstance(array, (ak._v2.highlevel.Array, ak._v2.highlevel.Record)):\n        return array.layout.parameters\n\n    elif isinstance(\n        array,\n        (ak._v2.contents.Content, ak._v2.record.Record),\n    ):\n        return array.parameters\n\n    elif isinstance(array, ak._v2.highlevel.ArrayBuilder):\n        return array.snapshot().layout.parameters\n\n    elif isinstance(array, ak.layout.ArrayBuilder):\n        return array.snapshot().parameters\n\n    else:\n        return {}\n", "path": "src/awkward/_v2/operations/ak_parameters.py"}], "after_files": [{"content": "# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE\n\nimport awkward as ak\n\nnp = ak.nplike.NumpyMetadata.instance()\n\n\ndef fields(array):\n    \"\"\"\n    Extracts record fields or tuple slot numbers from `array` (many types\n    supported, including all Awkward Arrays and Records).\n\n    If the array contains nested records, only the outermost record is\n    queried. If it contains tuples instead of records, this function outputs\n    string representations of integers, such as `\"0\"`, `\"1\"`, `\"2\"`, etc.\n    The records or tuples may be within multiple layers of nested lists.\n\n    If the array contains neither tuples nor records, this returns an empty\n    list.\n    \"\"\"\n    with ak._v2._util.OperationErrorContext(\n        \"ak._v2.fields\",\n        dict(array=array),\n    ):\n        return _impl(array)\n\n\ndef _impl(array):\n    layout = ak._v2.operations.to_layout(array, allow_record=True, allow_other=False)\n    return layout.fields.copy()\n", "path": "src/awkward/_v2/operations/ak_fields.py"}, {"content": "# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE\n\nimport copy\nimport numbers\n\nimport awkward as ak\n\nnp = ak.nplike.NumpyMetadata.instance()\n\n\ndef parameters(array):\n    \"\"\"\n    Extracts parameters from the outermost array node of `array` (many types\n    supported, including all Awkward Arrays and Records).\n\n    Parameters are a dict from str to JSON-like objects, usually strings.\n    Every #ak.layout.Content node has a different set of parameters. Some\n    key names are special, such as `\"__record__\"` and `\"__array__\"` that name\n    particular records and arrays as capable of supporting special behaviors.\n\n    See #ak.Array and #ak.behavior for a more complete description of\n    behaviors.\n    \"\"\"\n    with ak._v2._util.OperationErrorContext(\n        \"ak._v2.parameters\",\n        dict(array=array),\n    ):\n        return _impl(array)\n\n\ndef _impl(array):\n    if isinstance(array, (ak._v2.highlevel.Array, ak._v2.highlevel.Record)):\n        return _copy(array.layout.parameters)\n\n    elif isinstance(\n        array,\n        (ak._v2.contents.Content, ak._v2.record.Record),\n    ):\n        return _copy(array.parameters)\n\n    elif isinstance(array, ak._v2.highlevel.ArrayBuilder):\n        return array.snapshot().layout.parameters\n\n    elif isinstance(array, ak.layout.ArrayBuilder):\n        return array.snapshot().parameters\n\n    else:\n        return {}\n\n\ndef _copy(what):\n    if all(isinstance(x, (str, numbers.Real)) for x in what.values()):\n        return what.copy()\n    else:\n        return copy.deepcopy(what)\n", "path": "src/awkward/_v2/operations/ak_parameters.py"}]}