# Claude Code Project Context

## Code Quality Rules

- **Audit before PR**: Scrutinize every code change before opening a PR. Review the diff, check for unintended side effects, verify that variable names and logic match their intent (e.g., a variable named `largeTableVolume` must actually contain the large-side volume, not the small side).
- **Right place, right abstraction**: Before writing new logic, think about whether it belongs in the current file or should live in an existing module. Don't duplicate logic that already exists in the cost model, detectors, or volume estimator. If a function reimplements something the cost model already does, use the cost model.
- **Tests for every bug fix**: Always add unit tests that catch any bug being fixed. The test should fail without the fix and pass with it. This prevents regressions.
- **Never change a test unless behavior changes**: Do not modify an existing unit test unless the code it tests is also changing in the same commit. If a test fails, investigate the code — the test is likely correct.
- **Keep specs current**: When implementation diverges from a spec (different API shape, different algorithm, changed behavior), update the spec at `~/projects/specs/cylint/` immediately so it reflects what was actually built. Stale specs cause future work to be built on wrong assumptions.

## Specs & Design Docs

Project specs live outside the repo at `~/projects/specs/cylint/`.
Consult these when starting work on new features or when implementation
context is needed.

## Tech Stack

- Scala 2.13, cross-built with 2.12
- SBT 1.9.7
- circe for JSON
- scalatest for tests
- No Spark dependency in the analyzer (plans are parsed from JSON)

## Project Layout

Two independent sbt projects in one repo:
- **cluster-yield-ci** (root) — analyzer CLI, fat JAR
- **plan-extractor/** — extraction library for user pipelines (Spark `provided`)

## Key Conventions

- Detectors implement the `Detector` trait (per-plan) or are snapshot-level objects (like `ConfigAntiPatternDetector`)
- Findings use `costNature` to classify as "savings" (deterministic) or "exposure" (risk-bounded)
- `rootCause` on findings enables umbrella/evidence pattern to prevent double-counting
- Cost waterfall sequences findings per-plan to show composed savings
- All findings get `planLabel` metadata for waterfall grouping
