testing-changes
riekelt/principal-engineer
Determine what tests a behavior change requires and verify test coverage is sufficient.
What is testing-changes?
This skill guides you through deciding which tests a change owes—whether it's a feature, bug fix, or refactor. Use it when reviewing whether a diff's test changes match its behavior changes, especially for changes that seem "too small to test."
- Identify tests required for behavior changes, bug fixes, and refactors
- Verify regression tests go red against unfixed code and green after the fix
- Check that test assertions discriminate—actually fail if the code is broken
- Ensure edge cases and failure paths discovered during review are tested by name
- Validate that invariant tests exist for aggregates on critical paths
- Confirm each task names its verify command for reproducible testing
How to install testing-changes
npx skills add https://github.com/riekelt/principal-engineer --skill testing-changes- The principal-engineering skill (required background)
- Familiarity with writing-unit-tests skill for test craft
How to use testing-changes
- 1.When a behavior change lands, check whether the test diff is empty—if so, flag it as a review finding
- 2.For bug fixes, write the regression test to go red against unfixed code, then green after the fix
- 3.List the concrete edge cases and failure paths your change touches, then verify each has a named test
- 4.Run the verify command named in the task to confirm tests actually catch the change
- 5.Break the code once per assertion to confirm the test goes red; restore it and verify green
Use cases
- Reviewing a pull request where behavior changed but the test diff is empty
- Deciding what regression tests to write when fixing a bug
- Verifying a refactor truly changes no behavior by confirming existing tests pass unmodified
- Checking that edge cases surfaced in code review are covered by named test scenarios
- Ensuring failure-path behavior is tested when changes affect error handling
- Code reviewers evaluating test sufficiency
- Engineers writing tests for behavior changes
- Tech leads verifying quality gates and test coverage
- Teams practicing principal engineering and test-driven development
testing-changes FAQ
Any change that alters what the code does: features, bug fixes, error handling, and edge-case logic. A pure refactor is the opposite—existing tests must pass unmodified.
A one-line change can reach behavior no test covers. The regression stays silent until someone audits it. Every behavior change needs a test that would fail if the change were reverted.
A test that fails in a gate you own must be fixed, never silenced. Weakening assertions, deleting tests, or skipping them to ship converts a detected defect into an undetected one.
Break the code once to confirm the test goes red, then restore it and confirm the test goes green. If the test passes regardless, it proves nothing.
No—test-first is a workflow choice. This skill governs what must exist when the change ships, regardless of the order you wrote it in.
Full instructions (SKILL.md)
Source of truth, from riekelt/principal-engineer.
name: testing-changes description: Use when deciding what tests a change needs - a feature, a bug fix, a refactor, any behavior change - or when reviewing whether a diff's tests are sufficient. Encodes tests-change-with-behavior, the bug-regression pattern, and assertion discrimination. Use whenever behavior changes and the test diff is empty, especially when the change is "too small to test".
Testing changes
REQUIRED BACKGROUND: the principal-engineering skill. Test craft lives in writing-unit-tests; this skill governs which tests a change owes.
Overview
A test is the executable form of a claim about behavior. A change that alters behavior without touching tests is a claim nobody wrote down. Two failure modes follow: the green suite over code that could not work, and the test or gate that never ran.
Tests a change owes
- Tests change with behavior, in the same change. An empty test diff on a behavior change is a review finding, not a style preference. A pure refactor owes the opposite proof: the existing tests still pass unmodified, which is what makes it a refactor.
- A bug fix ships its regression test. Named after the failure mode, not the ticket. The author shows both halves: red against the unfixed code, green against the fix. A regression test that never went red proves only that it compiles.
- Scenarios are concrete and include the surfaced edges. The edge cases that grounding and review turned up go into tests by name; the happy path alone tests the demo, not the change. When the change's risk is in the failure path, the failure path gets the tests (see
handling-failures: it requires a logged, typed failure, and that surfacing is behavior a test owes). - Every task carries its targeted verify command. The task names the verify command that proves this change, runnable alone and stated where the reviewer can run it. "The suite passed" vouches for nothing the suite never covered.
- Assertions must discriminate. A test that passes regardless of the change proves nothing. Break the code once, confirm the test goes red, then restore it. Non-discriminating assertions are how suites stay green over broken behavior.
- Aggregates that must reconcile get invariant tests. Anything on the project's declared critical paths (see the risk tiers in
principal-engineering) that sums, derives, or mirrors other data gets more than point examples: the test asserts the reconciliation itself (the conservation pattern), the aggregate equals what the raw records imply.
The red-test rule
A red test in a gate you own gets fixed, never silenced: weakening the assertion, deleting the test, or marking it skipped to ship is converting a detected defect into an undetected one. Changing the test is legitimate exactly when the test asserted the old, wrong behavior, and the change says so explicitly. Attribute the origin first, then fix the test regardless of whose it is; "pre-existing" is a footnote, never an excuse (see verifying-before-done).
Tests a change does not owe
- Tests for unreachable edges (see
scoping-changes: fencing what cannot happen is dead code with good intentions). - Tests of framework internals or generated code. Test your use of them at the boundary you own.
- A test-first process: whether tests come first is workflow (a test-first workflow skill, where the project installs one, governs that); this skill governs what must exist when the change ships, whichever order produced it.
Common mistakes
- "Too small to test." A one-line change reaches behavior no test covers, and the regression stays silent until someone audits it.
- Testing the fix without reproducing the bug. Red-before-green is the half that proves the test sees the defect.
- Counting coverage by feel. Count the changed behaviors against the tests naming them (the same counting rule as the documentation-coverage count under "Keeping documents true" in the technical-writer plugin's
technical-writing/references/truth.md). - Adding the test that discriminates against nothing, ever: an assertion no plausible defect could fail. Distinct from the legitimate pinning test that deliberately passes against both old and new code to guard unchanged adjacent behavior from overcorrection; a pinning test says that is what it is for.
Related skills
More from riekelt/principal-engineer and the wider catalog.

verifying-before-done
Verify every completion claim by driving the change at its surface and running the verify command before declaring done.

writing-unit-tests
Behavior-first unit testing: one claim per test, deterministic setup, mocks only at external boundaries.

adding-dependencies
Systematic framework for adding, vetting, updating, and removing dependencies with cost-aware decision-making.

grounding-before-coding
Map real code and data before writing—ground every claim in evidence before any change.

diagramming-processes
Diagram business processes, workflows, and system interactions as maintainable source code.

documenting-contracts
Document HTTP APIs, message contracts, and file formats with exhaustive wire-level detail at the right abstraction level.