diff --git a/__main__.py b/__main__.py
index 9939195e2928140fde7176c927841a62ac07ac94..f9e72a897a76a2b004c5d458ac01ec7cbc05d0d6 100755
--- a/__main__.py
+++ b/__main__.py
@@ -79,6 +79,8 @@ from .tests.basic.basic import BASIC_TESTS
 from .tests.asgn3.availability.availability_basic import AVAILABILITY_TESTS
 from .tests.asgn3.causal_consistency.causal_basic import CAUSAL_TESTS
 from .tests.asgn3.eventual_consistency.convergence_basic import CONVERGENCE_TESTS
+# from .tests.asgn3.view_change.view_change_basic import VIEW_CHANGE_TESTS
+from .tests.proxy.basic_proxy import PROXY_TESTS
 
 TEST_SET = []
 TEST_SET.append(TestCase("hello_cluster", hello_cluster))
@@ -86,6 +88,8 @@ TEST_SET.extend(BASIC_TESTS)
 TEST_SET.extend(AVAILABILITY_TESTS)
 TEST_SET.extend(CAUSAL_TESTS)
 TEST_SET.extend(CONVERGENCE_TESTS)
+TEST_SET.extend(PROXY_TESTS)
+# TEST_SET.extend(VIEW_CHANGE_TESTS)
 
 # set to True to stop at the first failing test
 FAIL_FAST = True
diff --git a/tests/proxy/basic_proxy.py b/tests/proxy/basic_proxy.py
new file mode 100644
index 0000000000000000000000000000000000000000..3dd87d3fa06d9fad19b432b129ee340bcec4827f
--- /dev/null
+++ b/tests/proxy/basic_proxy.py
@@ -0,0 +1,43 @@
+from ...utils.containers import ClusterConductor
+from ...utils.testcase import TestCase
+from ...utils.util import Logger
+from ..helper import KVSMultiClient, KVSTestFixture
+from ...utils.kvs_api import DEFAULT_TIMEOUT
+
+def basic_proxy(conductor: ClusterConductor, dir, log: Logger):
+    with KVSTestFixture(conductor, dir, log, node_count=4) as fx:
+        c = KVSMultiClient(fx.clients, "client", log)
+        conductor.add_shard("shard1", conductor.get_nodes([0, 1]))
+        conductor.add_shard("shard2", conductor.get_nodes([2, 3]))
+        fx.broadcast_view(conductor.get_shard_view())
+        # test 1
+        # put 50 keys (at least one proxy expected here)
+        # get_all() on one shard
+        # then ask the other shard for that key (proxy MUST happen here)
+
+        node_to_put = 0
+        base_key = "key"
+        for i in range(0, 51):
+            r = c.put(node_to_put, f"{base_key}{i}", f"{i}", timeout=10)
+            assert r.ok, f"expected ok for new key, got {r.status_code}"
+            node_to_put += 1
+            node_to_put = node_to_put % 4
+
+        r = c.get_all(0, timeout=10) # should get all of shard 1's keys
+        assert r.ok, f"expected ok for get, got {r.status_code}"
+        res = r.json()["items"]
+        print("res-- {}", res)
+
+        return True, "ok"
+    
+def partitioned_shards(conductor: ClusterConductor, dir, log: Logger):
+    with KVSTestFixture(conductor, dir, log, node_count=4) as fx:
+        ###
+        # test 2
+        # partition the shards
+        # put a bunch of keys
+        # we MUST probablistically encounter some hanging there. 
+        # have a time out where if it doesnt hang after like 50 keys, then its just wrong.
+        return True, "ok"
+
+PROXY_TESTS = [TestCase("basic_proxy", basic_proxy)]
\ No newline at end of file
diff --git a/utils/containers.py b/utils/containers.py
index dae84e411e8ef06906d47d7c8e99eea63d8a3ae8..894dbd281f25808892f6ba59dd3900f949b644ea 100644
--- a/utils/containers.py
+++ b/utils/containers.py
@@ -107,7 +107,7 @@ class ClusterConductor:
 
     def dump_all_container_logs(self, dir):
         self.log("dumping logs of kvs containers")
-        container_pattern = "^kvs_.*"
+        container_pattern = f"^kvs_{self.group_id}_.*"
         container_regex = re.compile(container_pattern)
 
         containers = self._list_containers()
@@ -143,6 +143,17 @@ class ClusterConductor:
             error_prefix=f"failed to remove container {name}",
         )
 
+    def _remove_containers(self, names: list[str]) -> None:
+        if len(names) == 0:
+            return
+        self.log(f"removing containers {names}")
+        run_cmd_bg(
+            self._make_remove_cmd(names[0]) + names[1:],
+            verbose=True,
+            error_prefix=f"failed to remove containers {names}",
+        )
+
+
     def _remove_network(self, name: str) -> None:
         # remove a single network
         self.log(f"removing network {name}")
@@ -184,10 +195,12 @@ class ClusterConductor:
         # cleanup containers
         self.log(f"  cleaning up {'group' if group_only else 'all'} containers")
         containers = self._list_containers()
-        for container in containers:
-            if container and container_regex.match(container):
-                self._remove_container(container)
-
+        containers_to_remove = [
+            container
+            for container in containers
+            if container and container_regex.match(container)
+        ]
+        self._remove_containers(containers_to_remove)
         # cleanup networks
         self.log(f"  cleaning up {'group' if group_only else 'all'} networks")
         networks = self._list_networks()