Baseline & Normalization
Raw signal values (like “500 lines of churn”) aren’t meaningful on their own. Is 500 lines a lot? It depends on your repository’s normal activity level. Codemetry’s baseline and normalization system solves this.
Why Baseline Matters
Section titled “Why Baseline Matters”Consider two repositories:
- Repo A: Typical day has 50-100 lines of churn
- Repo B: Typical day has 500-1000 lines of churn
A day with 500 lines of churn is:
- Extreme for Repo A (10x normal)
- Average for Repo B (typical activity)
Without baseline comparison, Codemetry couldn’t distinguish between normal and abnormal activity for your specific project.
How Baseline Works
Section titled “How Baseline Works”Building the Baseline
Section titled “Building the Baseline”Codemetry analyzes the previous N days (default: 56) to build a statistical baseline:
Baseline Period (56 days) Analysis Window───────────────────────────────── ───────────────[day -56] ... [day -2] [day -1] [target day] ↓ Collect signals for each day ↓ Compute distributions ↓ Store mean, stddev, percentilesFor each signal, the baseline stores:
- Mean: Average value over the baseline period
- Standard deviation: Spread of values
- Sorted values: For percentile calculations
Normalization
Section titled “Normalization”Each day’s signals are normalized against the baseline:
Z-score — How many standard deviations from the mean:
z = (value - mean) / stddevPercentile — Where this value ranks in the baseline distribution:
pctl = (count of baseline values <= current value) / total * 100Example
Section titled “Example”If your baseline for change.churn shows:
- Mean: 200 lines
- Standard deviation: 100 lines
A day with 450 lines of churn would have:
- Z-score: (450 - 200) / 100 = 2.5 (2.5 standard deviations above normal)
- Percentile: ~95th (higher than 95% of baseline days)
Baseline Configuration
Section titled “Baseline Configuration”baseline_days
Section titled “baseline_days”Controls how much history is used for comparison:
'baseline_days' => 56, // Default: 8 weeks| Setting | Behavior |
|---|---|
| Shorter (14-28) | More reactive to recent changes, less stable |
| Default (56) | Good balance of stability and responsiveness |
| Longer (90+) | Very stable, may not reflect recent patterns |
CLI Override
Section titled “CLI Override”php artisan codemetry:analyze --days=7 --baseline-days=30Baseline Caching
Section titled “Baseline Caching”Computing baselines is expensive (analyzes 56+ days of commits). Codemetry caches results:
Cache location:
- Primary:
<repo>/.git/codemetry/cache-baseline.json - Fallback:
sys_get_temp_dir()/codemetry/<repo-id>/cache-baseline.json
Cache invalidation: The cache is automatically invalidated when:
baseline_dayschanges- Provider list changes
- Configuration hash changes
You don’t need to manually clear the cache.
Normalized Signal Names
Section titled “Normalized Signal Names”In JSON output, normalized values appear with prefixes:
| Raw Signal | Normalized Keys |
|---|---|
change.churn |
norm.change.churn.z, norm.change.churn.pctl |
change.scatter |
norm.change.scatter.z, norm.change.scatter.pctl |
followup.fix_density |
norm.followup.fix_density.z, norm.followup.fix_density.pctl |
How Scoring Uses Normalization
Section titled “How Scoring Uses Normalization”The scoring algorithm uses percentiles to determine penalties:
| Condition | Effect |
|---|---|
| Churn at p95+ | -20 points |
| Churn at p90-95 | -12 points |
| Scatter at p90+ | -10 points |
| Fix density at p95+ | -25 points |
| Churn ≤p25 AND fix density ≤p25 | +5 points (reward) |
This means “high” and “low” are always relative to your repository’s norms.
Edge Cases
Section titled “Edge Cases”New Repositories
Section titled “New Repositories”With limited history, baseline may be sparse:
- Fewer than baseline_days of commits = smaller sample
- Distributions may be less stable
- Confidence scores reflect this uncertainty
Inactive Periods
Section titled “Inactive Periods”Days with zero commits are included in baseline:
- Weekends, holidays affect the distribution
- A Monday with “normal” activity may score differently than expected
- Consider this when interpreting weekend vs. weekday scores
Major Project Changes
Section titled “Major Project Changes”After significant changes (new team, major pivot):
- Old baseline may not reflect new patterns
- Consider temporarily shortening
baseline_days - Or clear cache and let new patterns emerge