From f338babc2e35f9f2e16b0c0f5ec21af4cbdabe9c Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Sun, 25 Oct 2026 20:22:57 -0700 Subject: [PATCH] docs(agents): adopt the fleet's narrowed design-principles directives (zackees/ci.yml#163) --- CLAUDE.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index fbfbf090..778dd887 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -56,12 +56,24 @@ Do not pipe pytest through `| tail -N` if you want streaming output; it buffers - Lint command: `bash lint`. - Test command: `bash test` or targeted subsets above. -- Prefer native Rust implementations and fail-loud behavior over silent Python fallbacks. +- Prefer native Rust implementations; fail-loud behavior is Design principle 6 below. - Do not add backwards-compat hacks for code paths that no longer exist. - For deterministic in-product render checks, use `fastled --test` with the `--test-*` screenshot, interval, log, and timeout flags. This uses the shipped Tauri viewer and exits automatically; no browser harness is needed. +## Design principles (fleet directives, zackees/ci.yml#163) + +Agent and review guidance from zackees/ci.yml `docs/policy-rust.md` ("Design principles, narrowed"). Not enforced by ci-lint; no rule ID. + +1. **Search before you add.** Before adding a resolver, detector, predicate, guard or path helper, `rg` for an existing one. Reuse it, or say in the PR why it does not fit. +2. **Conflicting implementations get a research issue, not an inline winner.** If the same concept is implemented more than once with observably different behaviour and fixing it needs a design decision, file `research: N conflicting implementations of X -- which is canonical?` listing every copy (`file:line`) and what the difference does to real input; cross-reference it and carry on with your task. Copies that behave identically are a refactor, not an issue. +3. **Keep behaviour changes and refactors apart.** Separate commits, preferably separate PRs, never one mixed diff. +4. **Refactor first only when you would grow a giant function.** If a fix would add more than 50 lines to a function already over 200 lines, extract first in a separate behaviour-preserving change with characterization tests written first (RED -> GREEN). Otherwise fix it where it belongs; no unrequested restructures. +5. **Function and file size follow the complexity ratchet (`RUST-018`).** Until it is wired into this workspace's `Cargo.toml`, new functions stay under clippy's `too_many_lines` (100) and `cognitive_complexity` (25). A function carrying an `#[expect]` must not grow; delete the `expect` once it is back under. Never split a file with `include!` fragments to dodge a length ceiling. Before splitting a hot file, check `git branch -a --contains` for in-flight branches -- a split is a rename and conflicts destructively. +6. **Fail fast, and delete before you abstract.** Reject invalid input at the boundary with a typed error; never fall back silently to a degraded path (that includes silent Python fallbacks for Rust-owned paths). Prefer deleting code to adding a layer. No new trait until there are two real implementations (a test double does not count). +7. **Existing boundaries beat generic DRY.** Platform modules, Dylint-enforced layering (`dylints/ban_std_pathbuf`), crate boundaries and documented deliberate copies win over removing duplication. Do not copy code across a crate boundary to get around it -- say the boundary hurts. An undocumented copy is a finding under 2; a documented one is not. + ## Common Gotchas - The installed `fastled` CLI on PATH may be a Python compatibility shim or stale script; the bundled native binary is `fastled[.exe]`.