diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml
index cf376fa8..d9c13bd1 100644
--- a/dm_control/mjcf/schema.xml
+++ b/dm_control/mjcf/schema.xml
@@ -2193,7 +2193,7 @@
-
+
@@ -2232,7 +2232,7 @@
-
+
@@ -2260,7 +2260,7 @@
-
+
@@ -2291,7 +2291,7 @@
-
+
@@ -2322,7 +2322,7 @@
-
+
@@ -2372,7 +2372,7 @@
-
+
@@ -2400,7 +2400,7 @@
-
+
@@ -2431,7 +2431,7 @@
-
+
@@ -2486,7 +2486,7 @@
-
+
@@ -3128,6 +3128,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3182,7 +3204,7 @@
-
+
diff --git a/dm_control/mjcf/schema_test.py b/dm_control/mjcf/schema_test.py
index 1eda0e8c..6f52630d 100644
--- a/dm_control/mjcf/schema_test.py
+++ b/dm_control/mjcf/schema_test.py
@@ -187,5 +187,46 @@ def constructible(spec_node, path):
+ '\n'.join(failures[:20]))
+class SchemaRegressionTest(absltest.TestCase):
+ """Declarations that MuJoCo accepts must stay representable in PyMJCF."""
+
+ def test_contact_sensor_parses_and_compiles(self):
+ xml_string = """
+
+
+
+
+
+
+
+
+
+
+ """
+ root = mjcf.from_xml_string(xml_string)
+ physics = mjcf.Physics.from_mjcf_model(root)
+ self.assertEqual(physics.model.nsensor, 1)
+ self.assertEqual(root.find('sensor', 'cs').geom1.name, 'g')
+
+ def test_jointinparent_is_scoped_on_attach(self):
+ child = mjcf.RootElement(model='child')
+ body = child.worldbody.add('body', name='b')
+ body.add('joint', name='j', type='hinge')
+ body.add('geom', name='g', size=[0.1])
+ child.actuator.add('general', name='a', jointinparent='j')
+ parent = mjcf.RootElement(model='parent')
+ parent.attach(child)
+ self.assertIn('jointinparent="child/j"', parent.to_xml_string())
+ physics = mjcf.Physics.from_mjcf_model(parent)
+ self.assertEqual(physics.model.nu, 1)
+
+ def test_custom_numeric_accepts_array_data(self):
+ root = mjcf.RootElement(model='m')
+ root.custom.add('numeric', name='x', data=[1, 2, 3])
+ physics = mjcf.Physics.from_mjcf_model(root)
+ self.assertEqual(physics.model.nnumericdata, 3)
+
+
if __name__ == '__main__':
absltest.main()