Add YAGNI guidance to agent instructions
diff --git a/.claude/skills/pre-pr/SKILL.md b/.claude/skills/pre-pr/SKILL.md index 56db5a5..81c2330 100644 --- a/.claude/skills/pre-pr/SKILL.md +++ b/.claude/skills/pre-pr/SKILL.md
@@ -11,45 +11,36 @@ - `BASE` = `master` unless the user names another base. - `git diff --name-only $(git merge-base HEAD $BASE)..HEAD` -- If NO C sources changed (only docs / `.claude/` / tools): say so, and run a minimal software-only gate — `boards = [stm32f407disco]`, no HIL — unless the user asks for more. ## 2. Map changes to boards -- `python3 tools/ci_select.py --base $BASE test/hil/tinyusb.json` → JSON with the affected - bsp `families`, the affected rig `boards`, and per-file `reasons`. `full: true` means a - broad/infra change. -- Affected families = `families` ∪ the family of every name in `boards`. Neither half is - enough alone: only the port and bsp rules fill `families` (a class/core/example change - reports boards but no families), and `boards` only ever names rig boards (an off-rig driver - change — `dcd_samx7x.c` → `same7x`, `boards: {}` — would never be compiled). +- `python3 tools/ci_select.py --base $BASE test/hil/tinyusb.json` → JSON with independent + top-level HIL and nested `build` selections. +- `buildBoards`: when `build.full` is false, sample one board per `build.families`; prefer a + rig-roster board of that family, else the first entry in `hw/bsp/<family>/boards/`. When + `build.full` is true, use `stm32f407disco` + `raspberry_pi_pico` as the broad representative + set. +- A non-default build target selected by the changed path must run through its existing + command (for example, `tinyusb_metrics` for `tools/metrics.py`). A default board sweep is + not evidence for a target it does not execute; report the target unverified if the current + workflow cannot express it. +- `hilBoards`: derive only from the top-level HIL selection, never from `buildBoards`. When + top-level `full` is false, sample one board per family from the keys of top-level `boards`; + when it is true, use the broad representative set above. Run HIL only if the rig is reachable + per `.claude/skills/hil/SKILL.md`. - A board's family is the `hw/bsp/<family>/boards/<board>/` directory holding it. - - When `full: true`, `boards` names every rig board and carries no signal — use `families` - alone there, plus the representative set below. -- Sample ONE board per affected family: prefer a rig-roster board of that family, else the - first entry in `hw/bsp/<family>/boards/`. - Rig roster: `python3 -c "import json;print([b['name'] for b in json.load(open('test/hil/tinyusb.json'))['boards']])"` -- Add the representative set `stm32f407disco` + `raspberry_pi_pico` when `full: true` (broad - change — class/core/common/infra). -- Cap at 4 boards and tell the user which families the cap dropped. A broad change affects ~20 - families, so the order matters: keep `stm32f407disco` and `raspberry_pi_pico` first whenever - their families are affected, then fill from the remaining families (spread across vendors — - don't let one vendor's family names take every slot). The list must NEVER end up empty — - final fallback is `[stm32f407disco]` (full-check throws on an empty list). -- Docs-only (`full: false`, no families, no boards) keeps §1's minimal software-only gate. +- Cap the union of both lists at 4 boards and report what the cap dropped; spread the sample + across vendors. +- Empty selections: run `pre-commit run --all-files` plus the smallest targeted check for changed tooling; skip board build/HIL. +- A non-empty selection yielding no sampled board is a mapping failure. -## 3. HIL boards +## 3. Launch -- `hilBoards` = chosen boards that are on the rig roster. This host must be able to reach the rig (per `.claude/skills/hil/SKILL.md`: host `ci`/`tusb` = local, any other host (dev PC) = remote). If none qualify, run software-only. +If the unique union of `buildBoards` and `hilBoards` is non-empty, invoke the Workflow tool: +`{ name: 'full-check', args: { boards: [...new Set([...buildBoards, ...hilBoards])], hilBoards, base: BASE } }` -## 4. Launch - -Invoke the Workflow tool: - -``` -{ name: 'full-check', args: { boards: [...], hilBoards: [...], base: BASE } } -``` - -## 5. Summarize +## 4. Summarize - Per-stage table: unit / build:<board> / size / pvs, then HIL per board — pass/fail with the first error for each failure. - If the hardware result has non-empty `locked` (a CI job held those boards): ask the user to choose **Force now** (re-invoke `hil-validate` with `force: true` for those boards; user accepts the risk of colliding with a mid-test CI job), **Keep waiting** (re-invoke `hil-validate` for them after a few minutes; ask again if still locked), or **Accept** the partial verdict. Never force without the user's answer.
diff --git a/CLAUDE.md b/CLAUDE.md index ebe2ba6..b10654a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md
@@ -9,10 +9,10 @@ Bias toward caution over speed. For trivial tasks, use judgment. - **Think first** — state assumptions; ask if unclear; when a choice matters, name it and recommend one rather than picking silently or surveying every option. -- **Simplicity** — no features, abstractions, flexibility, or error handling beyond what was asked. If 200 lines could be 50, rewrite. +- Follow YAGNI. Reuse existing code, standard-library, and native-platform features before adding dependencies or abstractions. Prefer the smallest clear solution, but never sacrifice correctness, safety, or necessary tests. - **Surgical changes** — touch only what the task requires; match existing style; don't refactor working code; mention unrelated dead code rather than deleting it. Remove only orphans *your* changes created. - **Goal-driven** — turn tasks into verifiable goals ("write failing test, make it pass"). For multi-step work, state a brief `step → verify` plan. -- **Worktrees** — default to a git worktree for any branch or multi-step work; never switch the shared primary checkout's branch. Sessions run concurrently: switching the primary checkout mid-flight disrupts other sessions and can silently point a review, build, or commit at the wrong diff. Only trivial one-shot fixes may skip this. Standard location: `.worktrees/<branch-name>` at the repo root (gitignored), e.g. `git worktree add .worktrees/my-branch -b my-branch`. In a new worktree, symlink the dependency dirs (`lib/*`, `hw/mcu/*`, `tools/linkermap` — the keys of `deps_all` in `tools/get_deps.py`) to the primary checkout instead of re-cloning them; only if the branch needs a different dep revision, replace that one symlink with a real dir and run `get_deps.py` for it. +- **Worktrees** — For branch or multi-step work, run `git worktree add .worktrees/<branch> -b <branch>`; never switch the primary checkout. Symlink the `deps_all` paths from `tools/get_deps.py` to the primary checkout; replace only a dependency that needs a different revision, then run `get_deps.py` for it. ## Claude and Codex Collaboration