diff --git a/.claude/commands/green.md b/.claude/commands/green.md index de338c68..bc1b159b 100644 --- a/.claude/commands/green.md +++ b/.claude/commands/green.md @@ -52,6 +52,13 @@ The foundation of TDD is the Red-Green-Refactor cycle: - No anticipatory coding or extra features - Address the specific failure message +### Post-Green Verification + +Once the test passes, run the coverage tool scoped to **only the files you edited** and check for uncovered lines: + +- Any uncovered lines in files you edited are over-implementation — **delete them** +- Do not scope to the full test suite; focus only on what changed + 3. **Refactor Phase**: Improve code structure while keeping tests green - Only allowed when relevant tests are passing - Requires proof that tests have been run and are green diff --git a/AGENTS.md b/AGENTS.md index 07e276f3..2f443460 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,7 +11,7 @@ - Always run tests with an explicit path (e.g. uv run pytest tests/unit) — test runners discover all types by default. - Test coverage requirements are usually at 100%, so when running a subset of tests, always disable test coverage to avoid the test run failing for insufficient coverage. - Avoid magic values in comparisons in tests in all languages (like ruff rule PLR2004 specifies) -- Prefer using random values in tests rather than arbitrary ones (e.g. the faker library, uuids, random.randint) when possible. +- Prefer using random values in tests rather than arbitrary ones (e.g. the faker library, uuids, random.randint) when possible. For enums, pick randomly rather than hardcoding one value. - Avoid loops in tests — assert each item explicitly so failures pinpoint the exact element. When verifying a condition across all items in a collection, collect the violations into a list and assert it's empty (e.g., assert [x for x in items if bad_condition(x)] == []). - Key `data-testid` selectors off unique IDs (e.g. UUIDs), not human-readable names which may collide or change. @@ -20,13 +20,17 @@ - Before writing new mock/spy helpers, check the `tests/unit/` folder for pre-built helpers in files like `fixtures.py` or `*mocks.py` - When a test needs a fixture only for its side effects (not its return value), use `@pytest.mark.usefixtures(fixture_name.__name__)` instead of adding an unused parameter with a noqa comment - Use `__name__` instead of string literals when referencing functions/methods (e.g., `mocker.patch.object(MyClass, MyClass.method.__name__)`, `pytest.mark.usefixtures(my_fixture.__name__)`). This enables IDE refactoring tools to catch renames. +- **Never hand-write VCR cassette YAML files.** Cassettes must be recorded from real HTTP interactions by running the test once with `--record-mode=once` against a live external service: `uv run pytest --record-mode=once --no-cov`. The default mode is `none` — a missing cassette will cause an error, which is expected until recorded. +- **Never hand-edit syrupy snapshot files.** Snapshots are auto-generated — to create or update them, run `uv run pytest --snapshot-update --no-cov`. A missing snapshot causes the test to fail, which is expected until you run with `--snapshot-update`. When a snapshot mismatch occurs, fix the code if the change was unintentional; run `--snapshot-update` if it was intentional. +- **Never hand-write or hand-edit pytest-reserial `.jsonl` recording files.** Recordings must be captured from real serial port traffic by running the test with `--record` while the device is connected: `uv run pytest --record --no-cov`. The default mode replays recordings — a missing recording causes an error, which is expected until recorded against a live device. ## Tooling - Always use `uv run python` instead of `python3` or `python` when running Python commands. +- Prefer dedicated shell tools over `python3`/`python` for simple one-off tasks: use `jq` for JSON parsing, standard shell builtins for string manipulation, etc. Only reach for `python3` when no simpler tool covers the need. - Check .devcontainer/devcontainer.json for tooling versions (Python, Node, etc.) when reasoning about version-specific stdlib or tooling behavior. -- For frontend work, run commands via `pnpm` scripts from `frontend/package.json`. ✅ pnpm test-unit ❌ pnpm vitest ... or npx vitest ... -- When running terminal commands, execute exactly one command per tool call. Do not chain commands with &&, ||, ;, or & unless the user explicitly asks for it. Pipes (|) are allowed for output transformation (e.g., head, tail, grep). If two sequential commands are needed, run them in separate tool calls. Chained commands break the permission allow-list matcher and cause unnecessary permission prompts +- For frontend work, run commands via `pnpm` scripts from `frontend/package.json` — never invoke tools directly (not pnpm exec , npx , etc.). ✅ pnpm test-unit ❌ pnpm vitest ... or npx vitest ... +- When running terminal commands, execute exactly one command per tool call. Do not chain commands with &&, ||, ;, or & — this prohibition has no exceptions, even for `cd && ...` patterns. Use absolute paths instead of `cd` to avoid needing to chain. Pipes (|) are allowed for output transformation (e.g., head, tail, grep). If two sequential commands are needed, run them in separate tool calls. Chained commands break the permission allow-list matcher and cause unnecessary permission prompts - Never use backslash line continuations in shell commands — always write the full command on a single line. Backslashes break the permission allow-list matcher. diff --git a/extensions/context.py b/extensions/context.py index 294d6202..d4f27bcd 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -57,13 +57,15 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: ####### context["default_node_version"] = "24.11.1" context["nuxt_ui_version"] = "^4.5.1" - context["nuxt_version"] = "^4.3.1" + context["nuxt_version"] = ( + "~4.3.1" # some weird funkiness with Nuxt v4.4.2 and MagicString. trying to bump to Vitest v4 is possibly the answer, but initial attempt at that failed + ) context["nuxt_icon_version"] = "^2.2.1" context["typescript_version"] = "^5.9.3" context["playwright_version"] = "^1.58.2" - context["vue_version"] = "^3.5.28" + context["vue_version"] = "^3.5.30" context["vue_tsc_version"] = "^3.2.4" - context["vue_devtools_api_version"] = "^8.0.0" + context["vue_devtools_api_version"] = "^8.1.0" context["vue_router_version"] = "^5.0.3" context["dotenv_cli_version"] = "^11.0.0" context["faker_version"] = "^10.3.0" @@ -84,7 +86,7 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["vue_test_utils_version"] = "^2.4.6" context["nuxt_test_utils_version"] = "3.19.1" context["vue_eslint_parser_version"] = "^10.4.0" - context["happy_dom_version"] = "^20.8.3" + context["happy_dom_version"] = "^20.8.4" context["node_kiota_bundle_version"] = "1.0.0-preview.100" ####### # These are duplicated in the CI files for this repository