agentsclimarketplace

Lane policy

Skill xiaolai/tdd-guardian-for-claude/skills/tdd-guardian/lane-policy

Test-level taxonomy — which behavior belongs in a unit, integration, e2e, or contract lane, how lanes bind to gate triggers, and how each lane participates in coverage. Use when designing a test matrix, configuring lanes, or deciding where a given test should live.From its SKILL.md

Install
npx -y skills add xiaolai/tdd-guardian-for-claude --skill lane-policy

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 10 stars10 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

8.9 KB, as published. Nobody here has run it

Lane Policy

A lane is one test tier with its own command, its own trigger, and its own coverage participation. Lanes exist because test tiers have genuinely different costs: a suite that takes 90 seconds and needs a browser cannot gate every task completion, and a suite that takes 900 milliseconds should not wait for one that does.

This is a separate axis from the assertion hierarchy in policy-core. That hierarchy asks how strongly does this test verify anything. This skill asks at what level does this behavior get verified. A test can be Level 1 in a unit lane or Level 7 in an e2e lane; both questions must be answered for every test.

The four levels

LaneBoundaryTypical runtimeDefault triggerCoverage
unitIn-process, no I/O beyond a tmpdir< 60s total["taskCompleted", "commit"]include
integrationReal adapters — DB, HTTP, filesystem, containers1–5 min["commit"]include
e2eThe deployed system through its real interface5–30 min["push"]none
contractThe agreement between two servicesvaries by sideconsumer ["commit"], provider ["push"]none

Additional lanes when a repo warrants them: smoke (a handful of checks against a live environment, ["manual"]), load (["manual"]), security (["push"]).

Where a behavior belongs

Assign each behavior to the cheapest lane that can actually verify it. Not the cheapest lane it can be written in — the cheapest lane where a failure would be real.

BehaviorLaneWhy
Pure computation, formatting, parsingunitNo collaborator is involved
Validation and guard clausesunitThe rejection is the observable behavior
State machine transitionsunitState is in-process
Error mapping and retry logicunitInject the failure; the policy is the unit
SQL correctness, migrations, constraintsintegrationA mocked DB cannot violate a constraint
ORM query semantics, lazy loading, N+1integrationThe behavior lives in the driver, not your code
HTTP routing, middleware order, serialisationintegrationUse an in-process client — real routing, no port
Auth middleware actually rejecting a requestintegrationA mocked guard proves nothing
Transaction rollback and isolationintegrationOnly a real transaction has isolation
File and filesystem semanticsintegrationPermissions, encoding, and locks are real behavior
Container security defaultsintegrationInspect the created resource, never the mock args
A user flow across more than one screene2eThe flow is the unit
Client-side routing, hydration, focus managemente2eOnly a real browser has a real DOM
Third-party redirect handshakes (OAuth, payments)e2eThe other side is real
"The consumer's expectations still hold"contractNeither side alone can answer it

The rule that decides borderline cases

If the test would still pass when the real collaborator is broken, it belongs one lane higher.

A test that mocks the database and asserts expect(mockQuery).toHaveBeenCalledWith(sql) passes when the SQL is invalid. That behavior is not verified at unit level and must have an integration test, or it is not verified at all.

The mock-boundary obligation

policy-core requires that mocking a system boundary is paired with an integration test covering the real path. Lanes are what make that requirement checkable instead of aspirational.

When a unit test mocks a boundary:

  1. Name the boundary in the test matrix (Mock boundary: field).
  2. Name the integration test that covers the real path.
  3. That integration test lives in the integration lane.
  4. review-gate verifies the pairing exists.

A repo with mocked boundaries and no integration lane has an unmet obligation. That is a finding, not a style preference — say so during /tdd-guardian:init and during review.

Trigger assignment

Bind a lane by its cost and its dependencies, not by its name:

Lane characteristicsgateOn
Under ~60s, no external services["taskCompleted", "commit"]
Needs Docker or a database, 1–5 min["commit"]
Drives a browser or a deployed environment, over 5 min["push"]
Costs money per run, or hits a third-party sandbox["manual"]

Trigger semantics:

  • taskCompleted — the hook runs these lanes when Claude finishes a task. This is the tight loop; anything slow here makes the plugin unusable.
  • commit — checked for freshness before git commit. Not run automatically.
  • push — checked for freshness before git push, gh pr create, and publish commands. push subsumes commit: pushing requires everything a commit requires, plus the push lanes.
  • manual — only ever runs via /tdd-guardian:gate <lane>.

When unsure, choose the slower trigger. A fast suite on push is mildly annoying; a slow suite on taskCompleted makes people disable the plugin.

Coverage participation

coverage: "include" means the lane's report joins the merged total that thresholds are checked against. coverage: "none" means it does not.

Rules:

  1. Each contributing lane needs its own coverageSummaryPath. Two lanes writing the same file means the second overwrites the first, and coverage is silently undercounted.
  2. E2E lanes default to none. Browser coverage needs an instrumented build and a browser-side collector. Unless that already exists, an e2e lane contributes nothing, and configuring it as though it does corrupts the totals.
  3. Prefer per-line formats when more than one lane contributes. LCOV, Cobertura, JaCoCo, coverage.py JSON, and coverage-final.json carry per-line data and merge as a true union. Summary-only formats fall back to a weighted average that counts a shared line once per lane. The gate reports which method it used and flags the approximate one.
  4. Thresholds apply to the merge, not to any single lane. Do not set per-lane thresholds; that reintroduces the coupling lanes exist to remove.

Coverage does not transfer across lanes

An e2e suite that walks the whole application does not make the unit lane's uncovered branches covered. If e2e coverage is not collected, those branches are uncovered — that is accurate, not pessimistic. Adding e2e coverage to raise the number, without the instrumentation to make it real, is the coverage equivalent of a wiring-only test.

Anti-patterns

Anti-patternWhy it failsFix
One lane containing every testThe slowest test sets the feedback loop for every changeSplit by tier
E2E on taskCompletedEvery task waits minutes; the plugin gets disabledgateOn: ["push"]
E2E with coverage: "include" but no instrumentationThe report is missing, or empty and scored 100%coverage: "none"
An integration lane that mocks the databaseIt is a unit lane wearing a costumeUse a real DB or testcontainers
optional: true to silence a red suiteHides a real defect behind a flagFix the suite
A lane per package in a monorepo with a workspace runnerN× the setup cost, N× the config to maintainOne aggregate command
Retries as the fix for flakinessConverts a signal into noiseFix the race; see tooling-catalog/references/e2e.md
Thresholds set per laneRecreates the coupling lanes removeThreshold the merged total

Minimum viable configuration

A repo needs exactly one lane to be configured. Do not invent an integration lane for a pure library with no I/O, or an e2e lane for a CLI with no UI. Lanes describe what the repo has; they are not a checklist to fill in.

The honest progression:

Repo shapeLanes
Pure library, no I/Ounit
Library with filesystem or network adaptersunit, integration
Web serviceunit, integration
Web service with a UIunit, integration, e2e
Service in a mesh with declared consumersunit, integration, contract, e2e

Scope

Covers the test-level taxonomy — which behavior belongs in a unit, integration, e2e, or contract lane, how lanes bind to gate triggers, and how each lane participates in coverage.

Does NOT cover:

QuestionSkill
How strongly does this test verify anything?tdd-guardian:policy-core
What command runs this lane in language X?tdd-guardian:tooling-catalog
How are multi-lane coverage reports merged?tdd-guardian:coverage-gate
How is a lane detected and written to config?commands/shared/detect-tooling.md

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.