Skip to main content

beaver-build

Build robust test dams that catch bugs before they flood production. The beaver surveys the stream, gathers materials wisely, builds with care, reinforces thoroughly, and ships with confidence.

Aller à l'installation

Informations de source

Dépôt
AutumnsGrove/her-go
Dernière activité de la source
1 avril 2026 à 18:00
Langue détectée de SKILL.md
anglais
Étoiles
0
Forks
0

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Explorateur de fichiers
4 fichiers

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
beaver-build
description
Build robust test dams that catch bugs before they flood production. The beaver surveys the stream, gathers materials wisely, builds with care, reinforces thoroughly, and ships with confidence.
triggers
["User asks to \"write tests\" or \"add tests\"","User says \"test this\" or \"make sure this works\"","User calls `/beaver-build` or mentions beaver/building dams","Deciding what deserves testing","Reviewing existing tests for effectiveness","Bug needs to become a regression test","Asked to \"add tests\" without specific guidance","Evaluating whether tests are providing real value","Refactoring causes many tests to break (symptom of bad tests)"]
# beaver-build — Go Test Skill Build robust test dams. The beaver surveys the stream, gathers materials wisely, builds with care, reinforces thoroughly, and ships with confidence. ## The Dam — 5-Phase Pipeline ``` SURVEY → GATHER → BUILD → REINFORCE → FORTIFY ↓ ↲ ↓ ↲ ↓ Understand Decide Write Harden Ship with the code scope tests edges confidence ``` Every testing task flows through these phases. Don't skip SURVEY — building without understanding creates brittle dams that break on the first flood. --- ## Phase 1: SURVEY — Understand the Stream Before writing a single `func Test`, answer: 1. **What does this code do for the user?** Not how — what. A tool handler saves facts. The compactor trims history. The scrubber protects PII. Start from the user-visible behavior. 2. **What breaks if this fails?** A broken classifier lets garbage into the memory DB. A broken compactor blows context windows. A broken PII scrubber leaks phone numbers. Know the blast radius. 3. **How much confidence do we need?** A utility function that formats time needs light coverage. The SQL query builder that talks to the live DB needs heavy coverage. Match effort to risk. 4. **What already exists?** Check for existing `_test.go` files in the package. Read them. Don't duplicate. Build on what's there. **Load references:** - `references/testing-patterns.md` — understand the Testing Trophy and what to test - `references/hergo-test-infrastructure.md` — know what test utilities exist --- ## Phase 2: GATHER — Decide What Earns a Test Apply the **Confidence Test**: "Would I notice if this broke in production?" ### Skip (not worth the dam materials) | What | Why | |------|-----| | Trivial getters/setters | `func (c Config) GetModel() string` tests nothing useful | | Framework behavior | Trust that `cobra` routes commands, `tgbotapi` sends messages | | Implementation details | Internal struct field layout, private helper ordering | | One-off scripts | `cmd/setup` runs once — maintenance cost exceeds value | | Pure logging calls | Trust `charmbracelet/log` works | ### Test lightly (smoke test, happy path) | What | Why | |------|-----| | Config loading | One test that valid YAML parses; don't test every field | | Prompt assembly | Verify markers expand; don't test every template variation | | External API clients | Mock at the HTTP boundary, verify request shape | ### Test thoroughly (the dam's core) | What | Why | |------|-----| | Memory operations | Facts are the bot's long-term brain — correctness is critical | | Tool handlers | Each tool is a user-facing action with observable effects | | Classifier/parser logic | Wrong parse = garbage in DB or rejected valid facts | | Compaction algorithm | Wrong math = context window blowout or lost history | | PII scrubbing | Wrong scrub = leaked personal data or broken responses | | SQL queries | Wrong query = data corruption, injection vulnerability | | Context building | Wrong context = bot loses memory, personality breaks | **Load references:** - `references/testing-patterns.md` — decision tables for skip vs. test --- ## Phase 3: BUILD — Construct the Dam ### The Go Testing Toolkit This project uses Go's standard `testing` package. No testify, no gomock, no frameworks. This is intentional — stdlib tests are readable, portable, and have zero dependency overhead. **Core patterns (always use these):** - **Table-driven tests** for anything with multiple input/output cases - **`t.Helper()`** on every test helper function (fixes error line reporting) - **`t.Run()`** subtests for named cases within a table - **`t.TempDir()`** for throwaway file system fixtures - **`t.Cleanup()`** for deferred resource teardown - **`httptest.NewServer()`** for HTTP integration tests - **Real SQLite** (temp file) for database tests — don't mock the DB **Write tests following Arrange-Act-Assert:** ```go func TestParseClassifierResponse_PlainSave(t *testing.T) { // Arrange: set up the scenario response := "SAVE — real user preference" // Act: do the thing (ONE call) v := parseClassifierResponse(response) // Assert: check the outcome if !v.Allowed { t.Errorf("Allowed = false, want true") } if v.Type != "SAVE" { t.Errorf("Type = %q, want %q", v.Type, "SAVE") } } ``` The Act section should be **one call**. If it's longer, the test does too much. **Name tests so they explain what breaks:** ```go // GOOD — tells you what failed func TestEstimateTokens_EmptyStringReturnsZero func TestDBProxy_RejectsUnauthorizedTable func TestScrubber_PreservesNamesInTier1 // BAD — tells you nothing func TestTokens func TestDB func TestScrub1 ``` **One test, one reason to fail.** If a test checks five unrelated things, split it. ### Test Type Decision Tree ``` Is the function pure (input → output, no side effects)? ├─ YES → Table-driven unit test │ Example: parseClassifierResponse, estimateTokens, FormatTrace │ └─ NO → Does it touch the database? ├─ YES → Integration test with real temp SQLite │ Example: fact storage, context building, compaction │ └─ NO → Does it make HTTP calls? ├─ YES → httptest.NewServer with controlled responses │ Example: LLM client, search API, weather API │ └─ NO → Does it orchestrate multiple things? ├─ YES → Integration test with real dependencies │ Example: tool handler (needs DB + config) │ └─ NO → Simple unit test Example: config validation, string formatting ``` **Load references:** - `references/test-templates.md` — concrete templates for each test type - `references/hergo-test-infrastructure.md` — existing helpers to import --- ## Phase 4: REINFORCE — Harden the Dam ### Mock only at external boundaries If you're mocking something we wrote, reconsider. Mock at trust boundaries: | Mock this | Why | |-----------|-----| | OpenRouter API responses | Can't call real LLMs in tests | | Tavily/Open Library responses | External service, rate-limited | | Telegram bot API | Can't send real messages | | File system (sometimes) | Use `t.TempDir()` for real FS when possible | | DON'T mock this | Why | |-----------------|-----| | SQLite database | Use a real temp DB — that's where bugs hide | | Our own packages | If `memory.Store` is hard to test with, fix the API | | Config loading | Use a real temp YAML file | ### Turn every bug into a regression test The bug-to-test pipeline: 1. Bug reported (or discovered) 2. Reproduce: write a test that **captures the bug's conditions** 3. Verify: test **fails** (proves it catches the bug) 4. Fix: change the code 5. Verify: test **passes** (proves the fix works) 6. The test now guards that code path forever ### Edge cases worth checking - **Empty/nil inputs**: Empty string, nil slice, zero struct - **Boundary values**: Max tokens, empty history, single message - **Unicode/special chars**: Emoji in facts, HTML in traces, newlines in prompts - **Concurrent access**: If the code uses goroutines, test with `-race` - **Error paths**: DB connection fails, API returns 500, malformed JSON ### Keep tests co-located Tests live in the same package as the code they test: ``` memory/ ├── store.go ├── store_test.go ← right here, same package ├── context.go └── context_test.go ← right here, same package ``` This gives tests access to unexported functions (white-box testing), which is appropriate for unit tests. For black-box integration tests, use `package memory_test` (note the `_test` suffix) to test only the public API. --- ## Phase 5: FORTIFY — Ship with Confidence ### Mandatory verification before shipping ```bash # Run the package's tests go test ./path/to/package/... # Run ALL tests (do this before any PR) go test ./... # Run with race detector (catches concurrent bugs) go test -race ./... # Run vet (catches subtle bugs the compiler misses) go vet ./... ``` ### Self-review checklist Before marking tests as done, verify: ``` [ ] Tests describe behavior, not implementation details [ ] Each test has one clear reason to fail [ ] Test names explain what breaks when they fail [ ] Table-driven tests used for multiple input/output cases [ ] t.Helper() called in every helper function [ ] Mocks limited to external boundaries (APIs, not our own code) [ ] Real SQLite used for database tests (not mocked) [ ] Bug fixes include regression tests [ ] Tests run fast (seconds, not minutes) [ ] Error paths tested, not just happy paths [ ] go test -race passes [ ] go vet passes ``` ### Coverage check (optional, after tests pass) ```bash # Generate coverage report go test -coverprofile=coverage.out ./... # View in browser go tool cover -html=coverage.out ``` Coverage is a **signal**, not a target. 80% coverage with good tests beats 100% coverage with garbage tests. Don't chase the number — chase confidence. --- ## Reference Routing Each phase loads specific references. Don't read everything up front — load what you need when you need it. | Phase | Load | Why | |-------|------|-----| | SURVEY | `testing-patterns.md` | Understand Trophy shape, what matters | | SURVEY | `hergo-test-infrastructure.md` | Know what helpers exist | | GATHER | `testing-patterns.md` | Decision tables for skip vs. test | | BUILD | `test-templates.md` | Concrete Go templates to follow | | BUILD | `hergo-test-infrastructure.md` | Import paths for existing helpers | | REINFORCE | `testing-patterns.md` | Mocking rules, bug-to-test pipeline | | FORTIFY | Self-review checklist above | Quality gate |
Voir sur GitHub