diff --git a/AGENTS.md b/AGENTS.md index aca6075b0..45a3287a4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -98,3 +98,15 @@ This project follows the [Conventional Commits](https://www.conventionalcommits. - The `config.toml` in the repo root is the working config file; `rai-config-init` is only for pip-installed users, not developers using the repo. - The Streamlit configurator (`rai/frontend/configurator.py`) is an optional GUI; all configuration can be done by editing `config.toml` directly. - Many test modules import ROS 2 packages (`rclpy`, `geometry_msgs`, etc.) at module level, so ROS 2 must be sourced even to collect tests. + +## Fresh clone / correct worktree (PERMANENT — Daniel 2026-07-28) + +Before PR audit, main-comparison greps, salvage, rebase, or Cursor coding on this repo: + +1. `git remote -v` + `git rev-parse --show-toplevel` must match the intended `org/repo` (this Bartok9 repo or the upstream you are patching). +2. Prefer a disposable clone for read-only “still needed on main?” audits: `/tmp/-review-$$` via `gh repo clone … -- --depth=1`. +3. Existing clones OK only after fetch + correct branch tip; confirm PR-touched paths exist. +4. Wrong tree once → **re-clone**. Do not keep grepping a foreign or polluted worktree (openpi 2026-07-28). +5. Never `git reset --hard` on shared/production worktrees; delete disposable `/tmp` clones instead. +6. Full law: skill `upstream-pr-engineering` **§27** · clawd `AGENTS.md`. + diff --git a/src/rai_bench/rai_bench/manipulation_o3de/tasks/place_at_coord_task.py b/src/rai_bench/rai_bench/manipulation_o3de/tasks/place_at_coord_task.py index 69811fd3a..b55c77e7a 100644 --- a/src/rai_bench/rai_bench/manipulation_o3de/tasks/place_at_coord_task.py +++ b/src/rai_bench/rai_bench/manipulation_o3de/tasks/place_at_coord_task.py @@ -49,9 +49,21 @@ def __init__( Defaults to 0.02. """ super().__init__(logger) + if not isinstance(obj_type, str) or not obj_type.strip(): + raise ValueError("obj_type must be a non-empty string") + if ( + not isinstance(target_position, tuple) + or len(target_position) != 2 + or not all(isinstance(v, (int, float)) and math.isfinite(float(v)) for v in target_position) + ): + raise ValueError("target_position must be a pair of finite numbers") + if not isinstance(allowable_displacement, (int, float)) or not math.isfinite(float(allowable_displacement)): + raise ValueError("allowable_displacement must be a finite number") + if float(allowable_displacement) <= 0: + raise ValueError("allowable_displacement must be positive") self.obj_type = obj_type - self.target_position = target_position - self.allowable_displacement = allowable_displacement + self.target_position = (float(target_position[0]), float(target_position[1])) + self.allowable_displacement = float(allowable_displacement) @property def task_prompt(self) -> str: diff --git a/tests/rai_bench/manipulation_o3de/tasks/test_place_at_coords_task.py b/tests/rai_bench/manipulation_o3de/tasks/test_place_at_coords_task.py index 06735bf14..7ec024e01 100644 --- a/tests/rai_bench/manipulation_o3de/tasks/test_place_at_coords_task.py +++ b/tests/rai_bench/manipulation_o3de/tasks/test_place_at_coords_task.py @@ -60,3 +60,23 @@ def test_calculate_multiple_objects_none_correct() -> None: correct, incorrect = task.calculate_correct([e1, e2]) assert correct == 0 assert incorrect == 1 + +import math +import pytest + + +def test_reject_non_positive_allowable_displacement() -> None: + with pytest.raises(ValueError): + PlaceObjectAtCoordTask("carrot", (0.5, 0.5), allowable_displacement=0.0) + with pytest.raises(ValueError): + PlaceObjectAtCoordTask("carrot", (0.5, 0.5), allowable_displacement=-0.01) + + +def test_reject_empty_obj_type() -> None: + with pytest.raises(ValueError): + PlaceObjectAtCoordTask("", (0.5, 0.5)) + + +def test_reject_non_finite_target() -> None: + with pytest.raises(ValueError): + PlaceObjectAtCoordTask("carrot", (math.nan, 0.5))