|
10 | 10 |
|
11 | 11 | * **Tier 1** — classes in the unified contract: they (transitively) subclass |
12 | 12 | ``BaseTaskEnv`` / ``RLTaskEnv`` / ``ManagerBasedRVEnv``. Only these are checked. |
13 | | -* **Tier 3** — external/native passthrough adapters (modules under ``_native``/ |
14 | | - ``_passthrough`` or classes named ``Native*``/``Passthrough*``) are an |
15 | | - explicitly-exempt compatibility tier and are skipped. |
| 13 | +* **Tier 3** — external/native passthrough adapters under dedicated ``_native``/ |
| 14 | + ``_passthrough`` paths are an explicitly-exempt compatibility tier and skipped. |
| 15 | + (Exemption is PATH-based only — a first-party in-contract task is checked even |
| 16 | + if its class name starts with ``Native``; see ``_is_tier3``.) |
16 | 17 | * Non-task helpers (controllers, sensors, command/actuator managers, success |
17 | 18 | evaluators, sessions) are not in the inheritance graph to ``BaseTaskEnv`` and |
18 | 19 | are therefore ignored. |
|
68 | 69 | # blocks any NEW Tier-1 step()/close() override so the architecture cannot degrade |
69 | 70 | # while the existing ones are migrated. Remove an entry when you drop its override. |
70 | 71 | KNOWN_STEP_OVERRIDES = frozenset({ |
| 72 | + "libero/native_libero.py", # native LIBERO replay port (Tier-1 by base, kept explicit) |
| 73 | + "mujoco_playground/open_cabinet.py", |
| 74 | + "mujoco_playground/pick.py", |
71 | 75 | "beyondmimic/metasim/envs/base_legged_robot.py", |
72 | 76 | "calvin/base_table.py", |
73 | 77 | "humanoid/base/base_legged_robot.py", |
|
89 | 93 | "simpler_env/_metasim/place_task.py", |
90 | 94 | }) |
91 | 95 | KNOWN_CLOSE_OVERRIDES = frozenset({ |
| 96 | + "libero/native_libero.py", |
92 | 97 | "robosuite/robosuite_env.py", |
93 | 98 | }) |
94 | 99 |
|
@@ -126,11 +131,17 @@ def _in_contract(name: str, graph: dict[str, set[str]], seen: set[str] | None = |
126 | 131 |
|
127 | 132 |
|
128 | 133 | def _is_tier3(rel_path: str, class_name: str) -> bool: |
129 | | - """Native/passthrough adapters are an explicitly-exempt compatibility tier.""" |
| 134 | + """Native/passthrough adapters are an explicitly-exempt compatibility tier. |
| 135 | +
|
| 136 | + Exemption is PATH-based only (dedicated ``_native``/``_passthrough`` dirs/files). |
| 137 | + A NAME-based exemption (``Native*``/``Passthrough*``) was removed: it let |
| 138 | + first-party in-contract tasks (e.g. ``NativeLiberoEnv(BaseTaskEnv)``, which |
| 139 | + lives in ``libero/native_libero.py`` — not a ``_native/`` dir) silently dodge |
| 140 | + the contract. In-contract classes are now always checked regardless of name; |
| 141 | + only genuine adapters under ``_native``/``_passthrough`` paths are exempt. |
| 142 | + """ |
130 | 143 | p = "/" + rel_path |
131 | | - if "/_native/" in p or "_passthrough" in rel_path: |
132 | | - return True |
133 | | - return class_name.startswith(("Native", "Passthrough")) |
| 144 | + return "/_native/" in p or "_passthrough" in rel_path |
134 | 145 |
|
135 | 146 |
|
136 | 147 | def _reset_lacks_seed(fn: ast.FunctionDef) -> bool: |
@@ -207,7 +218,11 @@ def test_unified_bases_accept_seed(): |
207 | 218 | tree = ast.parse((_TASKS / rel).read_text(encoding="utf-8")) |
208 | 219 | for cls in (n for n in ast.walk(tree) if isinstance(n, ast.ClassDef)): |
209 | 220 | for fn in cls.body: |
210 | | - if isinstance(fn, ast.FunctionDef) and fn.name == "reset" and _reset_lacks_seed(fn): |
| 221 | + if ( |
| 222 | + isinstance(fn, (ast.FunctionDef, ast.AsyncFunctionDef)) |
| 223 | + and fn.name == "reset" |
| 224 | + and _reset_lacks_seed(fn) |
| 225 | + ): |
211 | 226 | regressed.append(rel) |
212 | 227 | assert not regressed, f"Base classes regressed to reset() without seed: {sorted(set(regressed))}" |
213 | 228 |
|
|
0 commit comments