We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[bug] Runtime error during SVI inference when using poutine.do()
### Issue Description

Setting: a simple model with 2 latent Gaussians z1 and z2, giving rise to x ~ N( z1+z2, I).

In this setting p(z2 | x, z1) should be the same as p(z2 | x, do(z1)). 

I wanted to check whether the current Pyro interface reflects this and it seems it does not.

My initial thought is that there is a difference in how .do() and .condition() broadcast the constants across the plate context.

### Environment

 - OS and python version: MacOS 10.14.6, Python: 3.8.6
 - PyTorch version: 1.9.0.dev20210502 (nightly version)
 - Pyro version: 1.6.0.

### Code Snippet

Replication code:
https://pastebin.com/Ki2PYX7z


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pyro/poutine/do_messenger.py`
Content:
```
1 # Copyright (c) 2017-2019 Uber Technologies, Inc.
2 # SPDX-License-Identifier: Apache-2.0
3 
4 import numbers
5 import warnings
6 
7 import torch
8 
9 from .messenger import Messenger
10 from .runtime import apply_stack
11 
12 
13 class DoMessenger(Messenger):
14     """
15     Given a stochastic function with some sample statements
16     and a dictionary of values at names,
17     set the return values of those sites equal to the values
18     as if they were hard-coded to those values
19     and introduce fresh sample sites with the same names
20     whose values do not propagate.
21 
22     Composes freely with :func:`~pyro.poutine.handlers.condition`
23     to represent counterfactual distributions over potential outcomes.
24     See Single World Intervention Graphs [1] for additional details and theory.
25 
26     Consider the following Pyro program:
27 
28         >>> def model(x):
29         ...     s = pyro.param("s", torch.tensor(0.5))
30         ...     z = pyro.sample("z", dist.Normal(x, s))
31         ...     return z ** 2
32 
33     To intervene with a value for site `z`, we can write
34 
35         >>> intervened_model = pyro.poutine.do(model, data={"z": torch.tensor(1.)})
36 
37     This is equivalent to replacing `z = pyro.sample("z", ...)` with
38     `z = torch.tensor(1.)`
39     and introducing a fresh sample site pyro.sample("z", ...) whose value is not used elsewhere.
40 
41     References
42 
43     [1] `Single World Intervention Graphs: A Primer`,
44         Thomas Richardson, James Robins
45 
46     :param fn: a stochastic function (callable containing Pyro primitive calls)
47     :param data: a ``dict`` mapping sample site names to interventions
48     :returns: stochastic function decorated with a :class:`~pyro.poutine.do_messenger.DoMessenger`
49     """
50     def __init__(self, data):
51         super().__init__()
52         self.data = data
53         self._intervener_id = str(id(self))
54 
55     def _pyro_sample(self, msg):
56         if msg.get('_intervener_id', None) != self._intervener_id and \
57                 self.data.get(msg['name']) is not None:
58 
59             if msg.get('_intervener_id', None) is not None:
60                 warnings.warn(
61                     "Attempting to intervene on variable {} multiple times,"
62                     "this is almost certainly incorrect behavior".format(msg['name']),
63                     RuntimeWarning)
64 
65             msg['_intervener_id'] = self._intervener_id
66 
67             # split node, avoid reapplying self recursively to new node
68             new_msg = msg.copy()
69             apply_stack(new_msg)
70 
71             # apply intervention
72             intervention = self.data[msg['name']]
73             msg['name'] = msg['name'] + "__CF"  # mangle old name
74 
75             if isinstance(intervention, (numbers.Number, torch.Tensor)):
76                 msg['value'] = intervention
77                 msg['is_observed'] = True
78                 msg['stop'] = True
79             else:
80                 raise NotImplementedError(
81                     "Interventions of type {} not implemented (yet)".format(type(intervention)))
82 
83         return None
84
```
--- 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/pyro/poutine/do_messenger.py b/pyro/poutine/do_messenger.py
--- a/pyro/poutine/do_messenger.py
+++ b/pyro/poutine/do_messenger.py
@@ -66,6 +66,7 @@
 
             # split node, avoid reapplying self recursively to new node
             new_msg = msg.copy()
+            new_msg["cond_indep_stack"] = ()  # avoid entering plates twice
             apply_stack(new_msg)
 
             # apply intervention

{"golden_diff": "diff --git a/pyro/poutine/do_messenger.py b/pyro/poutine/do_messenger.py\n--- a/pyro/poutine/do_messenger.py\n+++ b/pyro/poutine/do_messenger.py\n@@ -66,6 +66,7 @@\n \n             # split node, avoid reapplying self recursively to new node\n             new_msg = msg.copy()\n+            new_msg[\"cond_indep_stack\"] = ()  # avoid entering plates twice\n             apply_stack(new_msg)\n \n             # apply intervention\n", "issue": "[bug] Runtime error during SVI inference when using poutine.do()\n### Issue Description\r\n\r\nSetting: a simple model with 2 latent Gaussians z1 and z2, giving rise to x ~ N( z1+z2, I).\r\n\r\nIn this setting p(z2 | x, z1) should be the same as p(z2 | x, do(z1)). \r\n\r\nI wanted to check whether the current Pyro interface reflects this and it seems it does not.\r\n\r\nMy initial thought is that there is a difference in how .do() and .condition() broadcast the constants across the plate context.\r\n\r\n### Environment\r\n\r\n - OS and python version: MacOS 10.14.6, Python: 3.8.6\r\n - PyTorch version: 1.9.0.dev20210502 (nightly version)\r\n - Pyro version: 1.6.0.\r\n\r\n### Code Snippet\r\n\r\nReplication code:\r\nhttps://pastebin.com/Ki2PYX7z\r\n\n", "before_files": [{"content": "# Copyright (c) 2017-2019 Uber Technologies, Inc.\n# SPDX-License-Identifier: Apache-2.0\n\nimport numbers\nimport warnings\n\nimport torch\n\nfrom .messenger import Messenger\nfrom .runtime import apply_stack\n\n\nclass DoMessenger(Messenger):\n    \"\"\"\n    Given a stochastic function with some sample statements\n    and a dictionary of values at names,\n    set the return values of those sites equal to the values\n    as if they were hard-coded to those values\n    and introduce fresh sample sites with the same names\n    whose values do not propagate.\n\n    Composes freely with :func:`~pyro.poutine.handlers.condition`\n    to represent counterfactual distributions over potential outcomes.\n    See Single World Intervention Graphs [1] for additional details and theory.\n\n    Consider the following Pyro program:\n\n        >>> def model(x):\n        ...     s = pyro.param(\"s\", torch.tensor(0.5))\n        ...     z = pyro.sample(\"z\", dist.Normal(x, s))\n        ...     return z ** 2\n\n    To intervene with a value for site `z`, we can write\n\n        >>> intervened_model = pyro.poutine.do(model, data={\"z\": torch.tensor(1.)})\n\n    This is equivalent to replacing `z = pyro.sample(\"z\", ...)` with\n    `z = torch.tensor(1.)`\n    and introducing a fresh sample site pyro.sample(\"z\", ...) whose value is not used elsewhere.\n\n    References\n\n    [1] `Single World Intervention Graphs: A Primer`,\n        Thomas Richardson, James Robins\n\n    :param fn: a stochastic function (callable containing Pyro primitive calls)\n    :param data: a ``dict`` mapping sample site names to interventions\n    :returns: stochastic function decorated with a :class:`~pyro.poutine.do_messenger.DoMessenger`\n    \"\"\"\n    def __init__(self, data):\n        super().__init__()\n        self.data = data\n        self._intervener_id = str(id(self))\n\n    def _pyro_sample(self, msg):\n        if msg.get('_intervener_id', None) != self._intervener_id and \\\n                self.data.get(msg['name']) is not None:\n\n            if msg.get('_intervener_id', None) is not None:\n                warnings.warn(\n                    \"Attempting to intervene on variable {} multiple times,\"\n                    \"this is almost certainly incorrect behavior\".format(msg['name']),\n                    RuntimeWarning)\n\n            msg['_intervener_id'] = self._intervener_id\n\n            # split node, avoid reapplying self recursively to new node\n            new_msg = msg.copy()\n            apply_stack(new_msg)\n\n            # apply intervention\n            intervention = self.data[msg['name']]\n            msg['name'] = msg['name'] + \"__CF\"  # mangle old name\n\n            if isinstance(intervention, (numbers.Number, torch.Tensor)):\n                msg['value'] = intervention\n                msg['is_observed'] = True\n                msg['stop'] = True\n            else:\n                raise NotImplementedError(\n                    \"Interventions of type {} not implemented (yet)\".format(type(intervention)))\n\n        return None\n", "path": "pyro/poutine/do_messenger.py"}], "after_files": [{"content": "# Copyright (c) 2017-2019 Uber Technologies, Inc.\n# SPDX-License-Identifier: Apache-2.0\n\nimport numbers\nimport warnings\n\nimport torch\n\nfrom .messenger import Messenger\nfrom .runtime import apply_stack\n\n\nclass DoMessenger(Messenger):\n    \"\"\"\n    Given a stochastic function with some sample statements\n    and a dictionary of values at names,\n    set the return values of those sites equal to the values\n    as if they were hard-coded to those values\n    and introduce fresh sample sites with the same names\n    whose values do not propagate.\n\n    Composes freely with :func:`~pyro.poutine.handlers.condition`\n    to represent counterfactual distributions over potential outcomes.\n    See Single World Intervention Graphs [1] for additional details and theory.\n\n    Consider the following Pyro program:\n\n        >>> def model(x):\n        ...     s = pyro.param(\"s\", torch.tensor(0.5))\n        ...     z = pyro.sample(\"z\", dist.Normal(x, s))\n        ...     return z ** 2\n\n    To intervene with a value for site `z`, we can write\n\n        >>> intervened_model = pyro.poutine.do(model, data={\"z\": torch.tensor(1.)})\n\n    This is equivalent to replacing `z = pyro.sample(\"z\", ...)` with\n    `z = torch.tensor(1.)`\n    and introducing a fresh sample site pyro.sample(\"z\", ...) whose value is not used elsewhere.\n\n    References\n\n    [1] `Single World Intervention Graphs: A Primer`,\n        Thomas Richardson, James Robins\n\n    :param fn: a stochastic function (callable containing Pyro primitive calls)\n    :param data: a ``dict`` mapping sample site names to interventions\n    :returns: stochastic function decorated with a :class:`~pyro.poutine.do_messenger.DoMessenger`\n    \"\"\"\n    def __init__(self, data):\n        super().__init__()\n        self.data = data\n        self._intervener_id = str(id(self))\n\n    def _pyro_sample(self, msg):\n        if msg.get('_intervener_id', None) != self._intervener_id and \\\n                self.data.get(msg['name']) is not None:\n\n            if msg.get('_intervener_id', None) is not None:\n                warnings.warn(\n                    \"Attempting to intervene on variable {} multiple times,\"\n                    \"this is almost certainly incorrect behavior\".format(msg['name']),\n                    RuntimeWarning)\n\n            msg['_intervener_id'] = self._intervener_id\n\n            # split node, avoid reapplying self recursively to new node\n            new_msg = msg.copy()\n            new_msg[\"cond_indep_stack\"] = ()  # avoid entering plates twice\n            apply_stack(new_msg)\n\n            # apply intervention\n            intervention = self.data[msg['name']]\n            msg['name'] = msg['name'] + \"__CF\"  # mangle old name\n\n            if isinstance(intervention, (numbers.Number, torch.Tensor)):\n                msg['value'] = intervention\n                msg['is_observed'] = True\n                msg['stop'] = True\n            else:\n                raise NotImplementedError(\n                    \"Interventions of type {} not implemented (yet)\".format(type(intervention)))\n\n        return None\n", "path": "pyro/poutine/do_messenger.py"}]}