## Implementation Plan: Anti-Grind Safeguards (Tier 1) ### Objective Implement three immediate enforcement layers to mitigate automated grinding in the Code Farm game. ### Changes #### 1. Per-User Rate Limit on Game POST Actions **Files:** - `devplacepy/routers/game/index.py` – in `_respond_action()` (line ~60) - `devplacepy/routers/game/farm.py` – inside `water()` and `steal()` handlers **Details:** - Use a rolling-window rate limiter keyed by `user_uid`: max 30 requests per minute per user. - Implement via a simple in-memory dictionary (or reuse existing `rate_limit` utility if present; if not, add a lightweight decorator/function that stores timestamps per user). - Reject with HTTP 429 if limit exceeded (return JSON response with error message). - Apply to all game action endpoints: `_respond_action`, `water`, `steal`. #### 2. Per-Plot Harvest→Plant Cooldown (5 seconds) **Files:** - `devplacepy/database/schema.py` – add `cooldown_until` column (nullable datetime) to `game_plots` table (near line ~983-1017). - `devplacepy/services/game/store/actions.py`: - In `plant()` (line ~31): check `now < cooldown_until`; if so, raise a clear error. - In `harvest()` (line ~83): set `cooldown_until = now + 5 seconds` after successful harvest. **Details:** - The column addition requires a DB migration (Alembic or raw SQL). If no migration tool is present, add a raw ALTER TABLE statement to the deployment script or a one-time migration file. For this plan, assume a migration step is added inside `database/schema.py` or an existing migration system is used. - The cooldown check in `plant()` should only apply if the plot has been harvested recently (i.e., `cooldown_until` is set). Unharvested plots (cooldown_until NULL) are not blocked. #### 3. DevII CONFIRM_REQUIRED for High-Volume Actions **File:** - `devplacepy/services/devii/actions/catalog/game.py` **Details:** - Add `CONFIRM_REQUIRED = True` to the action definitions for `game_plant`, `game_harvest`, and `game_fertilize`. This forces DevII to ask the user before executing each instance of these actions. #### 4. Tests **Files:** - `tests/e2e/game/index.py` – add a test that verifies the rate limit kicks in after 30 rapid requests. - `tests/e2e/game/farm.py` – add a test that verifies water/steal rate limit. - `tests/unit/services/game/store.py` – add unit tests for cooldown: - Harvest sets cooldown_until. - Plant fails if cooldown active. - Plant succeeds after cooldown expires. - `tests/unit/services/devii/actions/catalog/game.py` – (create if not exists) verify that `CONFIRM_REQUIRED` flag is set for the three actions. ### Definition of Done - [ ] Rate limit is enforced in `_respond_action()` in `routers/game/index.py` and in water/steal handlers in `routers/game/farm.py`. Verify via test: sending 31 rapid requests as the same user returns 429 on the 31st. - [ ] `cooldown_until` column exists in `game_plots` table. Verify schema migration applied. - [ ] `plant()` rejects with error when plot cooldown is active (within 5 seconds after harvest). Verify via unit test. - [ ] `harvest()` sets `cooldown_until` to 5 seconds in the future on success. Verify via unit test. - [ ] DevII actions `game_plant`, `game_harvest`, `game_fertilize` have `CONFIRM_REQUIRED = True`. Verify via unit test or code inspection. - [ ] All existing unit tests pass: `pip install -e '.[dev]' -q && make test-unit`. (If PEP 668 error occurs, prepend `--break-system-packages` to pip command or use venv.) - [ ] Lint passes: `pip install -q ruff && ruff check .` (use `--break-system-packages` if needed). - [ ] No unintended changes to other files confirmed via `git diff --stat` (only the files listed above modified).