headroom/tests/test_output_savings_policy.py
JD Davis c29b4ba84f
refactor(output): isolate savings policy (#1947)
## Description

Extracts the output-savings stratification, holdout assignment,
conversation key, and transform-label helpers into a pure policy module
while preserving the existing `headroom.proxy.output_savings` public
imports. This keeps the estimator/ledger adapter focused on statistics
and persistence.

Closes #

## Type of Change

- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Performance improvement
- [x] Code refactoring (no functional changes)

## Changes Made

- Added `headroom.proxy.output_savings_policy` for pure savings policy
helpers.
- Re-exported the moved helpers from `headroom.proxy.output_savings` to
keep callers stable.
- Added direct tests for the extracted policy boundary.
- Kept the LiteLLM callback compatibility shim required for repo-wide
type checking on fresh branches.

## Testing

- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check .`)
- [x] Type checking passes (`mypy headroom`)
- [x] New tests added for new functionality
- [ ] Manual testing performed

### Test Output

```text
python -m pytest tests/test_output_savings_policy.py tests/test_output_savings.py tests/test_litellm_callback.py tests/test_compress_api.py::TestLiteLLMCallback -q
54 passed in 6.42s

python -m ruff check .
All checks passed!

python -m ruff format --check .
1095 files already formatted

python -m mypy headroom --ignore-missing-imports
Success: no issues found in 409 source files

gitleaks protect --staged --no-banner --redact
no leaks found
```

## Real Behavior Proof

- Environment: Windows, Python 3.13.13, local worktree based on
`headroomlabs/main`.
- Exact command / steps: ran the focused pytest set, Ruff lint/format
checks, mypy over `headroom`, and staged gitleaks scan.
- Observed result: all local checks passed; staged secret scan found no
leaks.
- Not tested: full CI matrix and deployment flows; those are covered by
GitHub Actions.

## Review Readiness

- [x] I have performed a self-review
- [x] This PR is ready for human review

## Checklist

- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md if applicable

## Screenshots (if applicable)

N/A

## Additional Notes

Documentation and changelog updates are not applicable for this internal
refactor. GitHub reported existing Dependabot alerts on the default
branch during push; this PR does not change dependencies, and the staged
secret scan is clean.
2026-07-10 23:42:11 -05:00

60 lines
1.7 KiB
Python

"""Tests for pure output savings policy helpers."""
from __future__ import annotations
from headroom.proxy.output_savings_policy import (
assign_arm,
conversation_key_from_body,
input_bucket,
model_family,
parse_stratum_label,
stratum_key,
stratum_label,
)
def test_stratum_key_is_most_to_least_specific() -> None:
key = stratum_key(
turn_kind="new_user_ask",
input_tokens=5000,
model="claude-opus-4-8",
has_tools=True,
)
assert key == "opus|new_user_ask|s|tools"
def test_input_bucket_and_model_family_are_coarse() -> None:
assert [input_bucket(v) for v in (0, 2_000, 8_000, 32_000, 200_000)] == [
"xs",
"s",
"m",
"l",
"xl",
]
assert model_family("claude-sonnet-4-6") == "sonnet"
assert model_family("unknown-model") == "other"
def test_assign_arm_is_stable_and_respects_extreme_holdouts() -> None:
assert assign_arm("conv-123", 0.0) == "treatment"
assert assign_arm("conv-123", 1.0) == "control"
assert assign_arm("conv-123", 0.5) == assign_arm("conv-123", 0.5)
def test_conversation_key_uses_response_create_payload() -> None:
http_body = {"model": "gpt-5", "input": "build a cache"}
ws_body = {
"type": "response.create",
"response": {"model": "gpt-5", "input": "build a cache"},
}
assert conversation_key_from_body(http_body) == conversation_key_from_body(ws_body)
def test_stratum_label_round_trips_arm_and_key() -> None:
key = "opus|code|m|tools"
assert parse_stratum_label(stratum_label("treatment", key)) == ("treatment", key)
assert parse_stratum_label(stratum_label("control", key)) == ("control", key)
assert parse_stratum_label("unrelated") is None