{
  "schema_version": "1",
  "id": "metaworld-sawyer-coffee-push-v3",
  "name": "Meta-World Sawyer coffee-push-v3 scripted controller",
  "summary": "Meta-World Sawyer coffee-push-v3 scripted controller. Bounded, source-pinned simulation with an explicit task contract and retained fixed-case outcomes.",
  "capabilities": [
    "simulation",
    "bounded-json",
    "metaworld",
    "scripted-policy"
  ],
  "aliases": [
    "sawyer",
    "metaworld",
    "scripted-policy"
  ],
  "source": {
    "repository": "https://github.com/Farama-Foundation/Metaworld",
    "commit": "c0dafaf1557f31cad3b96ba2b62462f45638f5a5",
    "archive_url": "https://codeload.github.com/Farama-Foundation/Metaworld/tar.gz/c0dafaf1557f31cad3b96ba2b62462f45638f5a5",
    "archive_sha256": "ea091176e3be68314432025d945fa7005f50cc82b319db3cc19374d37c6b52c0",
    "archive_bytes": 174769862,
    "authors": [
      "Original Metaworld contributors; preserve all pinned source and asset notices"
    ],
    "paths": [
      "LICENSE",
      "pyproject.toml",
      "metaworld/__init__.py",
      "metaworld/env_dict.py",
      "metaworld/sawyer_xyz_env.py",
      "metaworld/policies/policy.py",
      "metaworld/policies/action.py",
      "metaworld/policies/sawyer_coffee_push_v3_policy.py",
      "metaworld/envs/sawyer_coffee_push_v3.py"
    ]
  },
  "license": {
    "spdx": "MIT",
    "url": "https://github.com/Farama-Foundation/Metaworld/blob/c0dafaf1557f31cad3b96ba2b62462f45638f5a5/LICENSE",
    "verified": true,
    "scope": "Pinned first-party code terms. Preserve all upstream notices; robot assets and dependencies retain their separate licenses. Hub-authored wrapper is MIT."
  },
  "compatibility": [
    {
      "runtime": "metaworld",
      "runtime_version": "3.1.1",
      "robot": "sawyer",
      "controller": "scripted-policy",
      "observation": "privileged_simulator_state",
      "os": "linux",
      "architecture": "x86_64",
      "python": "3.11",
      "status": "hub_verified"
    }
  ],
  "observation": {
    "required": [
      "simulator_state"
    ],
    "privileged_state": true,
    "description": "Privileged simulator observations and goal/state feedback. No physical sensor validation."
  },
  "requirements": {
    "python": ">=3.11,<3.12",
    "packages": [
      "metaworld==3.1.1",
      "mujoco==3.3.0",
      "numpy==1.26.4",
      "gymnasium==1.2.0",
      "packaging==25.0"
    ],
    "hardware": [
      "Linux x86_64; CPU simulation; see retained receipt for the exact host environment"
    ],
    "rendering": "Headless. EGL libraries are required for MuJoCo imports; PushT uses SDL dummy video. No interactive display.",
    "api_keys": [],
    "network": [
      "Pinned source archive during preparation",
      "PyPI dependencies during explicit installation"
    ],
    "dependency_lock": "Direct runtime versions are pinned and measured. The receipt retains the complete environment freeze; prepare records the installed environment. System drivers are separate host requirements."
  },
  "invocation": {
    "entrypoint": "python run.py",
    "argv": [
      "{python}",
      "{recipe_dir}/run.py",
      "--source-dir",
      "{source_dir}",
      "--example"
    ],
    "inputs": {
      "seed": 0
    },
    "outputs": {
      "format": "single JSON object",
      "payload_selector": "outputs",
      "schema": {
        "type": "object",
        "required": [
          "success_window",
          "native_success",
          "steps",
          "control_effort",
          "hand_movement_m",
          "native_metrics"
        ],
        "properties": {
          "success_window": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "items": {
              "type": "boolean"
            }
          },
          "native_success": {
            "type": "boolean"
          },
          "steps": {
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          },
          "control_effort": {
            "type": "number",
            "minimum": 0,
            "maximum": 10000
          },
          "hand_movement_m": {
            "type": "number",
            "minimum": 0,
            "maximum": 10,
            "x-unit": "m"
          },
          "native_metrics": {
            "type": "array",
            "minItems": 0,
            "maxItems": 32,
            "items": {
              "type": "object",
              "required": [
                "name",
                "value"
              ],
              "properties": {
                "name": {
                  "type": "string",
                  "maxLength": 80
                },
                "value": {
                  "type": "number",
                  "minimum": -10000,
                  "maximum": 10000
                }
              },
              "additionalProperties": false
            }
          }
        },
        "additionalProperties": false
      }
    },
    "example": "Prepare explicitly; run --example or replace it with --input TASK.json. --describe reads the bounded contract without running simulation."
  },
  "interface": {
    "version": "1",
    "kind": "task",
    "abstraction_level": 2,
    "execution_domain": "simulation",
    "language": "python",
    "input_transport": "json_file_or_inline",
    "output_transport": "json_stdout",
    "output_selector": "outputs",
    "conventions": {
      "linear_unit": "m",
      "angular_unit": "rad",
      "time_unit": "s",
      "coordinate_frame": "right_handed_world_xyz; +z_up",
      "joint_order": "not_used",
      "quaternion_order": "not_used"
    },
    "input_schema": {
      "type": "object",
      "required": [
        "seed"
      ],
      "properties": {
        "seed": {
          "type": "integer",
          "minimum": 0,
          "maximum": 10000
        }
      },
      "additionalProperties": false
    },
    "output_schema": {
      "type": "object",
      "required": [
        "success_window",
        "native_success",
        "steps",
        "control_effort",
        "hand_movement_m",
        "native_metrics"
      ],
      "properties": {
        "success_window": {
          "type": "array",
          "minItems": 1,
          "maxItems": 20,
          "items": {
            "type": "boolean"
          }
        },
        "native_success": {
          "type": "boolean"
        },
        "steps": {
          "type": "integer",
          "minimum": 1,
          "maximum": 500
        },
        "control_effort": {
          "type": "number",
          "minimum": 0,
          "maximum": 10000
        },
        "hand_movement_m": {
          "type": "number",
          "minimum": 0,
          "maximum": 10,
          "x-unit": "m"
        },
        "native_metrics": {
          "type": "array",
          "minItems": 0,
          "maxItems": 32,
          "items": {
            "type": "object",
            "required": [
              "name",
              "value"
            ],
            "properties": {
              "name": {
                "type": "string",
                "maxLength": 80
              },
              "value": {
                "type": "number",
                "minimum": -10000,
                "maximum": 10000
              }
            },
            "additionalProperties": false
          }
        }
      },
      "additionalProperties": false
    },
    "preconditions": [
      "Use the exact recorded source, Linux Python 3.11 environment and pinned direct packages.",
      "No physical robot, network actuation or external robot credentials."
    ],
    "postconditions": [
      "All reported checks must be true and all output numbers finite.",
      "Success covers the declared goal and frozen cases, not arbitrary tasks or physical hardware."
    ],
    "failure_codes": [
      "invalid_input_or_environment",
      "execution_failed",
      "task_failed"
    ],
    "composition": {
      "depends_on": [],
      "automatic_frame_conversion": false,
      "automatic_hardware_execution": false
    },
    "origin_reference_ids": [
      "metaworld-metaworld-policies-sawyer-coffee-push-v3-policy-py"
    ],
    "origin_relationship": "prepared_from_the_same_pinned_model; inspect the declared controller and goal; no physical compatibility is inferred"
  },
  "completion": {
    "success_condition": "All declared goal and finite-state checks pass; exit 0 with task_complete. Five consecutive native task-success predicates within 500 dynamic simulation steps. Task-specific success definitions come from the pinned upstream environment; this is not a general manipulation score.",
    "timeout_seconds": 180,
    "failure_modes": [
      "Invalid input or source checksum",
      "Different pinned package version",
      "Unavailable runtime/driver",
      "Goal not reached within bounded steps"
    ],
    "stop_condition": "Terminate the adapter at the recorded timeout. No physical hardware is opened."
  },
  "preparation": {
    "recipe_path": "recipes/metaworld-sawyer-coffee-push-v3",
    "requirements_file": "recipes/metaworld-sawyer-coffee-push-v3/requirements.txt",
    "install_argv": [
      "{python}",
      "-m",
      "pip",
      "install",
      "--only-binary=:all:",
      "-r",
      "{recipe_dir}/requirements.txt"
    ],
    "execution_separate": true,
    "files": {
      "run.py": "# Hub-authored adapter: MIT. Upstream source/models retain their original licenses.\n\"\"\"Source template for standalone, bounded JSON recipe adapters (MIT, Hub authors).\n\nThe generator embeds this template and a reviewed backend in each published\nrecipe. Importing this template does not import or execute upstream source.\n\"\"\"\nimport argparse\nimport contextlib\nimport hashlib\nimport importlib.util\nimport io\nimport json\nimport math\nimport os\nfrom pathlib import Path\nimport random\nimport sys\n\n\nclass ContractError(ValueError):\n    pass\n\n\ndef validate_data(value, schema, path='$'):\n    \"\"\"Supported, published JSON Schema subset; bool is never a number.\"\"\"\n    kind = schema.get('type')\n    checks = {'object': lambda: isinstance(value, dict), 'array': lambda: isinstance(value, list),\n              'number': lambda: type(value) in (int, float) and math.isfinite(value),\n              'integer': lambda: type(value) is int, 'string': lambda: isinstance(value, str),\n              'boolean': lambda: isinstance(value, bool), 'null': lambda: value is None}\n    if kind and (kind not in checks or not checks[kind]()):\n        raise ContractError(path + ': expected ' + str(kind))\n    if 'enum' in schema and value not in schema['enum']:\n        raise ContractError(path + ': unsupported value')\n    if type(value) in (int, float):\n        if not math.isfinite(value) or value < schema.get('minimum', value) or value > schema.get('maximum', value):\n            raise ContractError(path + ': outside numeric bounds')\n    if isinstance(value, dict):\n        if len(value) > 32: raise ContractError(path + ': too many keys')\n        for name in schema.get('required', []):\n            if name not in value: raise ContractError(path + '.' + name + ': required')\n        props = schema.get('properties', {})\n        for name, item in value.items():\n            if name not in props and schema.get('additionalProperties') is False:\n                raise ContractError(path + '.' + name + ': unknown field')\n            validate_data(item, props.get(name, {}), path + '.' + name)\n    elif isinstance(value, list):\n        if not schema.get('minItems', 0) <= len(value) <= schema.get('maxItems', 4096):\n            raise ContractError(path + ': invalid array length')\n        for i, item in enumerate(value): validate_data(item, schema.get('items', {}), path + '[' + str(i) + ']')\n    elif isinstance(value, str) and len(value) > schema.get('maxLength', 4096):\n        raise ContractError(path + ': string too long')\n\n\ndef verify_source(root, spec):\n    root = Path(root).resolve()\n    for name, expected in spec['source_hashes'].items():\n        target = root / name\n        if target.is_symlink() or not target.resolve().is_relative_to(root) or not target.is_file():\n            raise ContractError('Pinned source missing or outside source root: ' + name)\n        if hashlib.sha256(target.read_bytes()).hexdigest() != expected:\n            raise ContractError('Pinned source checksum changed: ' + name)\n    return root\n\n\ndef load_upstream(root, relative):\n    \"\"\"Only a generator-pinned path is accepted; never a path from task input.\"\"\"\n    target = root / relative\n    for directory in [root, root / 'PathPlanning', target.parent]:\n        sys.path.insert(0, str(directory))\n    module_spec = importlib.util.spec_from_file_location('rsh_upstream', target)\n    module = importlib.util.module_from_spec(module_spec)\n    module_spec.loader.exec_module(module)\n    if hasattr(module, 'show_animation'): module.show_animation = False\n    return module\n\n\ndef clean_json(value):\n    if hasattr(value, 'tolist'): return clean_json(value.tolist())\n    if isinstance(value, dict): return {k: clean_json(v) for k,v in value.items()}\n    if isinstance(value, (tuple, list)): return [clean_json(v) for v in value]\n    if hasattr(value, 'item'): return clean_json(value.item())\n    if isinstance(value, float) and not math.isfinite(value): raise ContractError('Non-finite output')\n    return value\n\n\ndef adapter_main(spec, backend):\n    parser = argparse.ArgumentParser(description=spec['name'])\n    parser.add_argument('--source-dir')\n    group = parser.add_mutually_exclusive_group(required=True)\n    group.add_argument('--input', type=Path, help='UTF-8 JSON file; no code or paths inside task input')\n    group.add_argument('--input-json', help='Inline JSON task input')\n    group.add_argument('--example', action='store_true', help='Run the declared example input')\n    group.add_argument('--describe', action='store_true', help='Read the contract without importing upstream code')\n    args = parser.parse_args()\n    try:\n        if args.describe:\n            print(json.dumps({'skill_id': spec['id'], 'interface': spec['interface'], 'example_input': spec['example']}, allow_nan=False))\n            return 0\n        if args.input:\n            with args.input.open('rb') as stream: raw=stream.read(65537)\n        else: raw=args.input_json.encode() if args.input_json else None\n        if raw is not None and len(raw) > 65536: raise ContractError('Input exceeds 64 KiB')\n        data = json.loads(raw) if raw is not None else spec['example']\n        validate_data(data, spec['interface']['input_schema'])\n        if not args.source_dir: raise ContractError('--source-dir is required for execution')\n        root = verify_source(args.source_dir, spec)\n        os.environ['MPLBACKEND'] = 'Agg'\n        os.environ.setdefault('OMP_NUM_THREADS', '1')\n        random.seed(data.get('seed', 0))\n        # Upstream diagnostic prints do not contaminate the machine response.\n        with contextlib.redirect_stdout(sys.stderr):\n            outputs, checks = backend(root, data, spec)\n        outputs, checks = clean_json(outputs), clean_json(checks)\n        validate_data(outputs, spec['interface']['output_schema'])\n        if not checks or not all(type(v) is bool for v in checks.values()): raise ContractError('Invalid postcondition report')\n        ok = all(checks.values())\n        print(json.dumps({'schema_version':'1','skill_id':spec['id'],'status':'task_complete' if ok else 'task_failed',\n            'success':ok,'outputs':outputs,'checks':checks,'execution_domain':spec['interface']['execution_domain'],\n            'source_commit':spec['source_commit'],'interface_version':'1','hardware_execution':False}, allow_nan=False, separators=(',',':')))\n        return 0 if ok else 1\n    except (ContractError, ValueError, OSError, ImportError) as error:\n        print(json.dumps({'schema_version':'1','skill_id':spec['id'],'status':'failed','success':False,\n            'reason_code':'invalid_input_or_environment','message':str(error),'hardware_execution':False}, allow_nan=False))\n        return 2\n    except Exception as error:\n        print(json.dumps({'schema_version':'1','skill_id':spec['id'],'status':'failed','success':False,\n            'reason_code':'execution_failed','message':str(error)[:1000],'hardware_execution':False}, allow_nan=False))\n        return 1\n\n\n\"\"\"MIT: bounded runner for the pinned upstream goal-observable scripted policy.\"\"\"\ndef mainstream_backend(root,data,spec):\n    import importlib.metadata\n    import numpy as np\n    for pin in spec['packages']:\n        name,version=pin.split('==')\n        if importlib.metadata.version(name)!=version:raise ContractError('Pinned package version differs: '+name)\n    # Load the actual archived controllers and task implementation, not an\n    # unpinned policy with the same class name from a different installation.\n    sys.path.insert(0,str(root))\n    import metaworld\n    from metaworld.env_dict import ALL_V3_ENVIRONMENTS_GOAL_OBSERVABLE\n    from importlib import import_module\n    policy=getattr(import_module(spec['policy_module']),spec['policy_class'])()\n    env=ALL_V3_ENVIRONMENTS_GOAL_OBSERVABLE[spec['env_id']+'-goal-observable'](seed=data['seed'])\n    try:\n        obs,_=env.reset(seed=data['seed']);initial=obs[:3].copy();window=[];control=0.;finite=True\n        for step in range(500):\n            action=np.asarray(policy.get_action(obs),dtype=np.float64)\n            if action.shape!=(4,) or not np.isfinite(action).all():raise ContractError('Invalid policy action')\n            action=np.clip(action,env.action_space.low,env.action_space.high);control+=float(np.linalg.norm(action))\n            obs,reward,terminated,truncated,info=env.step(action)\n            finite=finite and bool(np.isfinite(obs).all() and math.isfinite(float(reward)))\n            window.append(bool(info.get('success',False)));window=window[-20:]\n            if len(window)>=5 and all(window[-5:]):break\n            if terminated or truncated:break\n        metrics=[{'name':k,'value':float(v)} for k,v in sorted(info.items()) if isinstance(v,(int,float,np.number)) and np.isfinite(v)]\n        complete=len(window)>=5 and all(window[-5:])\n        return {'success_window':window,'native_success':bool(info.get('success',False)),\n                'steps':step+1,'control_effort':control,'hand_movement_m':float(np.linalg.norm(obs[:3]-initial)),\n                'native_metrics':metrics}, {'sustained_native_task_predicate':complete,'finite_state':finite,\n                'nonzero_control':control>0,'physical_simulation_steps':step+1>=5}\n    finally:env.close()\n\nSPEC = json.loads('{\"id\":\"metaworld-sawyer-coffee-push-v3\",\"name\":\"Meta-World Sawyer coffee-push-v3 scripted controller\",\"backend\":\"metaworld\",\"operation\":\"scripted-policy\",\"adapter_template\":\"metaworld_policy\",\"interface\":{\"version\":\"1\",\"kind\":\"task\",\"abstraction_level\":2,\"execution_domain\":\"simulation\",\"language\":\"python\",\"input_transport\":\"json_file_or_inline\",\"output_transport\":\"json_stdout\",\"output_selector\":\"outputs\",\"conventions\":{\"linear_unit\":\"m\",\"angular_unit\":\"rad\",\"time_unit\":\"s\",\"coordinate_frame\":\"right_handed_world_xyz; +z_up\",\"joint_order\":\"not_used\",\"quaternion_order\":\"not_used\"},\"input_schema\":{\"type\":\"object\",\"required\":[\"seed\"],\"properties\":{\"seed\":{\"type\":\"integer\",\"minimum\":0,\"maximum\":10000}},\"additionalProperties\":false},\"output_schema\":{\"type\":\"object\",\"required\":[\"success_window\",\"native_success\",\"steps\",\"control_effort\",\"hand_movement_m\",\"native_metrics\"],\"properties\":{\"success_window\":{\"type\":\"array\",\"minItems\":1,\"maxItems\":20,\"items\":{\"type\":\"boolean\"}},\"native_success\":{\"type\":\"boolean\"},\"steps\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":500},\"control_effort\":{\"type\":\"number\",\"minimum\":0,\"maximum\":10000},\"hand_movement_m\":{\"type\":\"number\",\"minimum\":0,\"maximum\":10,\"x-unit\":\"m\"},\"native_metrics\":{\"type\":\"array\",\"minItems\":0,\"maxItems\":32,\"items\":{\"type\":\"object\",\"required\":[\"name\",\"value\"],\"properties\":{\"name\":{\"type\":\"string\",\"maxLength\":80},\"value\":{\"type\":\"number\",\"minimum\":-10000,\"maximum\":10000}},\"additionalProperties\":false}}},\"additionalProperties\":false},\"preconditions\":[\"Use the exact recorded source, Linux Python 3.11 environment and pinned direct packages.\",\"No physical robot, network actuation or external robot credentials.\"],\"postconditions\":[\"All reported checks must be true and all output numbers finite.\",\"Success covers the declared goal and frozen cases, not arbitrary tasks or physical hardware.\"],\"failure_codes\":[\"invalid_input_or_environment\",\"execution_failed\",\"task_failed\"],\"composition\":{\"depends_on\":[],\"automatic_frame_conversion\":false,\"automatic_hardware_execution\":false}},\"example\":{\"seed\":0},\"source_hashes\":{\"LICENSE\":\"a85291ff6ec82ee24b4218644df5d62522562e06acb8f17437513ef2136a3393\",\"pyproject.toml\":\"e8e481b95d3d26e31a33dbe8690036687755eee75d2c6ac07cd6d91aa144b70e\",\"metaworld/__init__.py\":\"8613586a1f5236a8c10079809d6ea94a2c2e597fcdb1fbd6241468419dba22d7\",\"metaworld/env_dict.py\":\"f9e6380a04d5c5c64f4d2e595a591692ec2a92af2613bb2ddd10d1567e61edf6\",\"metaworld/sawyer_xyz_env.py\":\"4282580b80befc557f67d25acffffec737ad0dae2c440601be76fc09139f351d\",\"metaworld/policies/policy.py\":\"bf07b7d6511a2973c125993e7d598ab2d9705fd21588d42b5c9e449e2580c208\",\"metaworld/policies/action.py\":\"0d4bf73b0505bf4e4e95e683bd0371111db7a5e25b1e255db9be9fdde606058e\",\"metaworld/policies/sawyer_coffee_push_v3_policy.py\":\"6ba96ce91108f02d972f751a907bac5f3191dcd9c406bc4cb4adbcecf397a413\",\"metaworld/envs/sawyer_coffee_push_v3.py\":\"9dc16aa4a87334fd24c5a30c6b64284733dbf2a0f2dc7ad577c6fa3dae449ed3\"},\"summary\":\"Meta-World Sawyer coffee-push-v3 scripted controller. Bounded, source-pinned simulation with an explicit task contract and retained fixed-case outcomes.\",\"observation_description\":\"Privileged simulator observations and goal/state feedback. No physical sensor validation.\",\"goal_scope\":\"Five consecutive native task-success predicates within 500 dynamic simulation steps. Task-specific success definitions come from the pinned upstream environment; this is not a general manipulation score.\",\"env_id\":\"coffee-push-v3\",\"policy_module\":\"metaworld.policies.sawyer_coffee_push_v3_policy\",\"policy_class\":\"SawyerCoffeePushV3Policy\",\"source_commit\":\"c0dafaf1557f31cad3b96ba2b62462f45638f5a5\",\"packages\":[\"metaworld==3.1.1\",\"mujoco==3.3.0\",\"numpy==1.26.4\",\"gymnasium==1.2.0\",\"packaging==25.0\"]}')\n\nif __name__ == \"__main__\":\n    raise SystemExit(adapter_main(SPEC, mainstream_backend))\n",
      "requirements.txt": "metaworld==3.1.1\nmujoco==3.3.0\nnumpy==1.26.4\ngymnasium==1.2.0\npackaging==25.0\n",
      "LICENSE": "MIT License\n\nCopyright (c) 2026 Superfast Robotics\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n",
      "LICENSE_SCOPE.md": "# Prepared execution adapter license\n\nThe Hub-authored adapter files in this recipe are MIT licensed; see LICENSE.\nThe source checkout is a separately pinned upstream work. Its original license,\ncopyright and required notices remain applicable. The catalog record's license\ndescribes that upstream source, not a replacement for this adapter's license.\nSeparately licensed dependencies, models, weights, data, firmware and services\nretain their own terms. An adapter's successful simulation or computation does\nnot grant rights to those assets or establish physical robot compatibility.\n"
    }
  },
  "evidence": {
    "level": "task_complete",
    "verified_by": "Hub finite-case Lambda execution harness",
    "date": "2026-10-20",
    "environment": {
      "scope": "simulation",
      "physical_robot": false,
      "platforms": [
        "linux"
      ]
    },
    "commands": [
      "python tools/verify_runtime_expansion.py --backend metaworld --source-cache SOURCE_CACHE --output OUTPUT"
    ],
    "result": "All 3 frozen cases completed against this exact adapter and source.",
    "artifacts": [
      "https://raw.githubusercontent.com/Superfast-Robotics/robot-skill-hub/f97266a5cdd2c600cd376397a54892f08290df20/evidence/runtime/diverse-sim-v1/metaworld-sawyer-coffee-push-v3.json"
    ],
    "runtime_verification": "task_complete",
    "contributor_reported": null,
    "hub_verification": {
      "runtime": "task_complete",
      "scope": "simulation",
      "adapter_sha256": "8333517efe58e53dadf15868c336f2c7514258e56e776bce0f72421b3f899a6b",
      "source_commit": "c0dafaf1557f31cad3b96ba2b62462f45638f5a5",
      "record_version": "1.0.0",
      "case_count": 3,
      "retained_failed_cases": 0
    }
  },
  "maintenance": {
    "record_version": "1.0.0",
    "last_checked": "2026-10-20",
    "upstream_status": "immutable_source_and_explicit_dependencies"
  },
  "contribution": {
    "allowed_paths": [
      "catalog/records/metaworld-sawyer-coffee-push-v3.json",
      "recipes/metaworld-sawyer-coffee-push-v3/run.py",
      "recipes/metaworld-sawyer-coffee-push-v3/requirements.txt",
      "docs/recipes/metaworld-sawyer-coffee-push-v3.md"
    ],
    "instructions": "Change the runtime expansion manifest/template, regenerate, and rerun all frozen cases. Preserve source/model/checkpoint licenses and distinguish simulation from hardware."
  }
}
