From 6cf253a2f40827f0947f867d5d163c45693885b5 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Tue, 17 Mar 2026 16:30:01 +0000 Subject: [PATCH 01/13] vcrpy --- AGENTS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 07e276f3..d2f92ab6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,6 +20,9 @@ - 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 From 55fdff5ed88e39f61e167082058cfa0d620629f6 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Tue, 17 Mar 2026 17:22:15 +0000 Subject: [PATCH 02/13] post green --- .claude/commands/green.md | 7 +++++++ 1 file changed, 7 insertions(+) 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 From b2dd1dd5cd3135f21b560d947c0ed6acebcb8cfb Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Wed, 18 Mar 2026 10:23:55 +0000 Subject: [PATCH 03/13] chain --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index d2f92ab6..eb54a7c1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -29,7 +29,7 @@ - Always use `uv run python` instead of `python3` or `python` when running Python commands. - 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 +- 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. From f5d3030f224d63c5c1ecd91cf76853c7540821be Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Wed, 18 Mar 2026 10:25:45 +0000 Subject: [PATCH 04/13] no exec --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index eb54a7c1..a21b6e9d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,7 +28,7 @@ ## Tooling - Always use `uv run python` instead of `python3` or `python` when running Python commands. - 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 ... +- 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. From a1ada6e2d1d2e91405bfcdfd797cd3baecefdeca Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Wed, 18 Mar 2026 10:33:17 +0000 Subject: [PATCH 05/13] jq --- AGENTS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AGENTS.md b/AGENTS.md index a21b6e9d..f3a9057c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,6 +27,7 @@ ## 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` — 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 From d4ad17934de0ce6ab74f8690e16c5aa73e9730dd Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Wed, 18 Mar 2026 10:37:06 +0000 Subject: [PATCH 06/13] enums --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index f3a9057c..d896e094 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 using 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. From 537f04da304652e249ceff0ca0c6aa66d8a564cf Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Wed, 18 Mar 2026 12:11:10 +0000 Subject: [PATCH 07/13] nuxt --- extensions/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/context.py b/extensions/context.py index 294d6202..169535ba 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -57,7 +57,7 @@ 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.4.2" context["nuxt_icon_version"] = "^2.2.1" context["typescript_version"] = "^5.9.3" context["playwright_version"] = "^1.58.2" From 725af090f568745c707fa83481382cae7978b174 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Wed, 18 Mar 2026 12:15:02 +0000 Subject: [PATCH 08/13] dom --- extensions/context.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/context.py b/extensions/context.py index 169535ba..d613382e 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -63,7 +63,7 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["playwright_version"] = "^1.58.2" context["vue_version"] = "^3.5.28" 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 +84,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 From ccf45ccd50e2f6193afba897b41e5b69d744b5bf Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Wed, 18 Mar 2026 12:36:21 +0000 Subject: [PATCH 09/13] vue --- extensions/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/context.py b/extensions/context.py index d613382e..bb32e26e 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -61,7 +61,7 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: 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.50" context["vue_tsc_version"] = "^3.2.4" context["vue_devtools_api_version"] = "^8.1.0" context["vue_router_version"] = "^5.0.3" From 7d715dde140fc97ef2f21b53cfeb170cc0e07432 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Wed, 18 Mar 2026 12:39:16 +0000 Subject: [PATCH 10/13] fix vue --- extensions/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/context.py b/extensions/context.py index bb32e26e..a60071a6 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -61,7 +61,7 @@ def hook(self, context: dict[Any, Any]) -> dict[Any, Any]: context["nuxt_icon_version"] = "^2.2.1" context["typescript_version"] = "^5.9.3" context["playwright_version"] = "^1.58.2" - context["vue_version"] = "^3.5.50" + context["vue_version"] = "^3.5.30" context["vue_tsc_version"] = "^3.2.4" context["vue_devtools_api_version"] = "^8.1.0" context["vue_router_version"] = "^5.0.3" From 12adccaa1ed0ad730fbf3567c2303c83aa5a5c18 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Wed, 18 Mar 2026 15:34:14 +0000 Subject: [PATCH 11/13] more next --- extensions/context.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions/context.py b/extensions/context.py index a60071a6..468cedb7 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -57,7 +57,9 @@ 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.4.2" + context["nuxt_version"] = ( + "~4.3.1" # some weird funkiness with Nuxt v4.4.3 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" From bdb2f4057223a3c9a2cd4feb253bf4381bbec8ef Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Wed, 18 Mar 2026 15:37:34 +0000 Subject: [PATCH 12/13] typo --- extensions/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/context.py b/extensions/context.py index 468cedb7..d4f27bcd 100644 --- a/extensions/context.py +++ b/extensions/context.py @@ -58,7 +58,7 @@ 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" # some weird funkiness with Nuxt v4.4.3 and MagicString. trying to bump to Vitest v4 is possibly the answer, but initial attempt at that failed + "~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" From 9be0eb35d7bea456fbdd234a58e934d65563d362 Mon Sep 17 00:00:00 2001 From: Eli Fine Date: Wed, 18 Mar 2026 18:21:39 +0000 Subject: [PATCH 13/13] wording --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index d896e094..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. For enums, pick randomly using rather than hardcoding one value. +- 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.