Skip to content

fix(mcp): show lifetime totals and label rolling session scope in headroom_stats#1428

Merged
JerrettDavis merged 2 commits into
headroomlabs-ai:mainfrom
rodboev:pr/1166-mcp-stats-lifetime-scope
Jun 30, 2026
Merged

fix(mcp): show lifetime totals and label rolling session scope in headroom_stats#1428
JerrettDavis merged 2 commits into
headroomlabs-ai:mainfrom
rodboev:pr/1166-mcp-stats-lifetime-scope

Conversation

@rodboev

@rodboev rodboev commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Description

headroom_stats currently formats only the rolling session view from /stats, so users see session numbers with no explicit scope label and no lifetime totals even though the proxy already exposes lifetime savings data.

This PR keeps the current session summary, labels it as rolling-session output, and appends lifetime totals from persistent_savings.lifetime. It stays formatting-only on an existing payload surface.

Closes #1166

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
  • Code refactoring (no functional changes)

Changes Made

  • label the existing headroom_stats session block as rolling-session output
  • append lifetime totals from the existing stats payload
  • add focused formatter regressions and fallback coverage
  • update CHANGELOG.md

Testing

  • Unit tests pass (uv run pytest tests/test_ccr_mcp_server.py -v)
  • Linting passes (uv run ruff check .)
  • Type checking passes (uv run mypy headroom) or explain N/A truthfully
  • New tests added for new functionality when applicable
  • Manual testing performed

Test Output

Focused local commands passed:
- uv run pytest tests/test_ccr_mcp_server.py -x -v
  9 passed, 1 skipped
- uv run ruff check headroom/ccr/mcp_server.py tests/test_ccr_mcp_server.py
  All checks passed
- uv run ruff format headroom/ccr/mcp_server.py tests/test_ccr_mcp_server.py --check
  2 files already formatted

Base proof on origin/main with the updated regression file:
- pytest -k "window_scoped"
  failed because the output still says "Headroom Session Summary"
- pytest -k "includes_lifetime_totals_from_persistent_savings"
  failed because the formatted text still has no "Lifetime Savings:" section

Not run locally:
- uv run mypy headroom
- Template-level broader commands `uv run pytest tests/test_ccr_mcp_server.py -v` and `uv run ruff check .`

Real Behavior Proof

  • Environment: focused HeadroomMCPServer._handle_stats() test payloads with and without persistent_savings.lifetime
  • Exact command / steps: run uv run pytest tests/test_ccr_mcp_server.py -x -v, specifically the new _handle_stats() regressions that feed summary-only, summary-plus-lifetime, missing-lifetime, and zero-lifetime payloads through the MCP stats formatter
  • Observed result: output contains Headroom Window-Scoped Session Summary, appends Lifetime Savings: when lifetime data is present, and omits that section cleanly when lifetime data is absent
  • Not tested: broader MCP output redesign beyond this formatter

Review Readiness

  • I have performed a self-review
  • This PR is ready for human review

Checklist

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

Additional Notes

  • Scoped to the MCP text surface only; dashboard and broader savings-window work stay out of scope.
  • Attribution: the issue body identified the exact mismatch between current headroom_stats output and the already-live lifetime stats payload.

@github-actions

Copy link
Copy Markdown
Contributor

PR governance

This PR follows the template and is marked ready for human review.

@github-actions github-actions Bot added the status: ready for review Pull request body is complete and the author marked it ready for human review label Jun 25, 2026

@JerrettDavis JerrettDavis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the MCP stats formatting change. It preserves the existing summary flow, makes the rolling/window scope explicit, and appends lifetime totals only when the existing persistent_savings.lifetime block is present. The fallback and zero-total cases are covered, and CI is green. Ready from my side.

@JerrettDavis JerrettDavis merged commit 1c0e152 into headroomlabs-ai:main Jun 30, 2026
23 checks passed
@github-actions github-actions Bot mentioned this pull request Jun 30, 2026
chopratejas pushed a commit that referenced this pull request Jul 3, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>0.29.0</summary>

##
[0.29.0](v0.28.0...v0.29.0)
(2026-07-03)


### Features

* **proxy:** add --lossless no-CCR mode with format-native compaction
([#1721](#1721))
([c75ebde](c75ebde))
* **stats:** surface Codex WS compression counters in /stats summary
([#1680](#1680))
([2fe19c3](2fe19c3))
* **transforms:** adaptive Otsu KEEP/DROP threshold (+ land relevance
split on main)
([#1726](#1726))
([eea667a](eea667a))


### Bug Fixes

* **bedrock:** fail fast when session-token auth lacks botocore
([#1553](#1553))
([54cfa36](54cfa36))
* **bedrock:** route ARNs via converse, named AWS profiles, and au. re…
([#1456](#1456))
([7d87aa2](7d87aa2))
* **ccr:** honor workspace dir for sqlite store
([#1564](#1564))
([96e1dfe](96e1dfe))
* **claude:** surface Remote Control proxy incompatibility
([#1610](#1610))
([4bf7f92](4bf7f92))
* **cli:** stop advertising unwired compression tuning env vars in
banner
([#1634](#1634))
([d5bf98d](d5bf98d))
* **codex:** avoid duplicate headroom provider config
([#1431](#1431))
([ddd4adf](ddd4adf))
* **compression:** reject lossy unmarked tool output in unit router path
([#1479](#1479))
([de24cd5](de24cd5))
* **cortex-code:** migrate to current Cortex REST API endpoints + add
e2e benchmarks
([#1474](#1474))
([f00ace6](f00ace6))
* **dashboard:** align token savings headline denominator
([#1653](#1653))
([646e705](646e705))
* **dashboard:** derive per-project setup URL from live origin
([#1511](#1511))
([e035aef](e035aef))
* **detection:** contain unidiff panic on orphaned +++ target line
([#1548](#1548))
([e386c09](e386c09))
* **evals:** CJK-aware F1 tokenization + token estimation
([#1527](#1527))
([99a8540](99a8540))
* **install:** close parent log fd in start_detached_agent
([#1576](#1576))
([816cb85](816cb85))
* **install:** use Windows-safe PID liveness probe in runtime_status
([#1544](#1544))
([#1560](#1560))
([6b227b9](6b227b9))
* **learn:** aggregate verbosity baselines across projects instead of
overwriting
([#1288](#1288))
([27a5468](27a5468))
* **mcp:** show lifetime totals and label rolling session scope in
headroom_stats
([#1428](#1428))
([1c0e152](1c0e152))
* **memory:** cap local embedder CPU thread oversubscription
([#198](#198))
([#1559](#1559))
([b84afbf](b84afbf))
* **memory:** singleflight LocalBackend init to stop cold-start races
([#1691](#1691))
([bec47a1](bec47a1))
* **openclaw:** detect uv-installed headroom binary in ~/.local/bin
([#1459](#1459))
([adaeb88](adaeb88))
* **opencode:** preserve custom OpenAI gateway paths
([#1596](#1596))
([c19347c](c19347c))
* **opencode:** route native providers + load transport plugin, fix
Serena context
([#1573](#1573))
([ad0034f](ad0034f))
* preserve anthropic passthrough tool order
([#1427](#1427))
([a932247](a932247))
* **proxy/auth:** match real Anthropic OAuth token prefix (sk-ant-oat)
([#1672](#1672))
([8cddf9b](8cddf9b))
* **proxy:** expose persistent savings metrics
([#1647](#1647))
([5fe4e7b](5fe4e7b))
* **proxy:** fail open when kompress saturation would exhaust
pre-upstream budget
([#1430](#1430))
([15ac650](15ac650))
* **proxy:** handle streaming CCR retrieval
([#1451](#1451))
([d337e3b](d337e3b))
* **proxy:** include system/tools/sampling in cache key
([#1473](#1473))
([312129a](312129a))
* **proxy:** preserve Responses passthrough bytes
([#1598](#1598))
([2a34a82](2a34a82))
* **proxy:** strip Codex lite header on the HTTP /responses path
([#1663](#1663))
([9fbd47b](9fbd47b))
* **proxy:** wire --compression-max-workers /
HEADROOM_COMPRESSION_MAX_WORKERS
([#1632](#1632))
([814ffa3](814ffa3))
* **savings:** count cache-read tokens in input cost estimate
([#1429](#1429))
([72ade37](72ade37))
* skip Magika backend on x86 CPUs without AVX2
([#1162](#1162))
([64783d8](64783d8))
* **transforms/content-router:** route grep/log output away from HTML
extractor
([#1719](#1719))
([0d18ef2](0d18ef2))
* **transforms:** bound native content detection with a Windows watchdog
([#575](#575))
([#1563](#1563))
([95abca3](95abca3))
* Vertex AI support for Claude Code with ANTHROPIC_VERTEX_BASE_URL
([#1393](#1393))
([cff7247](cff7247))
* **wrap:** detach the shared proxy on Windows so it survives an
ungraceful agent close
([#1464](#1464))
([6cba441](6cba441))
* **wrap:** preserve custom Vertex base URL
([#1477](#1477))
([75427bb](75427bb))
* **wrap:** remove rtk instructions from Codex AGENTS.md on unwrap
([#1604](#1604))
([c9d717c](c9d717c))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
JerrettDavis pushed a commit to peterlodri-sec/headroom that referenced this pull request Jul 14, 2026
…droom_stats (headroomlabs-ai#1428)

## Description

`headroom_stats` currently formats only the rolling session view from
`/stats`, so users see session numbers with no explicit scope label and
no lifetime totals even though the proxy already exposes lifetime
savings data.

This PR keeps the current session summary, labels it as rolling-session
output, and appends lifetime totals from `persistent_savings.lifetime`.
It stays formatting-only on an existing payload surface.

Closes headroomlabs-ai#1166

## Type of Change

- [x] 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
- [ ] Code refactoring (no functional changes)

## Changes Made

- label the existing `headroom_stats` session block as rolling-session
output
- append lifetime totals from the existing stats payload
- add focused formatter regressions and fallback coverage
- update `CHANGELOG.md`

## Testing

- [ ] Unit tests pass (`uv run pytest tests/test_ccr_mcp_server.py -v`)
- [ ] Linting passes (`uv run ruff check .`)
- [ ] Type checking passes (`uv run mypy headroom`) or explain N/A
truthfully
- [x] New tests added for new functionality when applicable
- [ ] Manual testing performed

### Test Output

```text
Focused local commands passed:
- uv run pytest tests/test_ccr_mcp_server.py -x -v
  9 passed, 1 skipped
- uv run ruff check headroom/ccr/mcp_server.py tests/test_ccr_mcp_server.py
  All checks passed
- uv run ruff format headroom/ccr/mcp_server.py tests/test_ccr_mcp_server.py --check
  2 files already formatted

Base proof on origin/main with the updated regression file:
- pytest -k "window_scoped"
  failed because the output still says "Headroom Session Summary"
- pytest -k "includes_lifetime_totals_from_persistent_savings"
  failed because the formatted text still has no "Lifetime Savings:" section

Not run locally:
- uv run mypy headroom
- Template-level broader commands `uv run pytest tests/test_ccr_mcp_server.py -v` and `uv run ruff check .`
```

## Real Behavior Proof

- Environment: focused `HeadroomMCPServer._handle_stats()` test payloads
with and without `persistent_savings.lifetime`
- Exact command / steps: run `uv run pytest tests/test_ccr_mcp_server.py
-x -v`, specifically the new `_handle_stats()` regressions that feed
summary-only, summary-plus-lifetime, missing-lifetime, and zero-lifetime
payloads through the MCP stats formatter
- Observed result: output contains `Headroom Window-Scoped Session
Summary`, appends `Lifetime Savings:` when lifetime data is present, and
omits that section cleanly when lifetime data is absent
- Not tested: broader MCP output redesign beyond this formatter

## 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
- [ ] I have commented my code, particularly in hard-to-understand areas
- [x] 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
- [ ] New and existing unit tests pass locally with my changes
- [x] I have updated the CHANGELOG.md if applicable

## Additional Notes

- Scoped to the MCP text surface only; dashboard and broader
savings-window work stay out of scope.
- Attribution: the issue body identified the exact mismatch between
current `headroom_stats` output and the already-live lifetime stats
payload.
JerrettDavis pushed a commit to peterlodri-sec/headroom that referenced this pull request Jul 14, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>0.29.0</summary>

##
[0.29.0](headroomlabs-ai/headroom@v0.28.0...v0.29.0)
(2026-07-03)


### Features

* **proxy:** add --lossless no-CCR mode with format-native compaction
([headroomlabs-ai#1721](headroomlabs-ai#1721))
([c75ebde](headroomlabs-ai@c75ebde))
* **stats:** surface Codex WS compression counters in /stats summary
([headroomlabs-ai#1680](headroomlabs-ai#1680))
([2fe19c3](headroomlabs-ai@2fe19c3))
* **transforms:** adaptive Otsu KEEP/DROP threshold (+ land relevance
split on main)
([headroomlabs-ai#1726](headroomlabs-ai#1726))
([eea667a](headroomlabs-ai@eea667a))


### Bug Fixes

* **bedrock:** fail fast when session-token auth lacks botocore
([headroomlabs-ai#1553](headroomlabs-ai#1553))
([54cfa36](headroomlabs-ai@54cfa36))
* **bedrock:** route ARNs via converse, named AWS profiles, and au. re…
([headroomlabs-ai#1456](headroomlabs-ai#1456))
([7d87aa2](headroomlabs-ai@7d87aa2))
* **ccr:** honor workspace dir for sqlite store
([headroomlabs-ai#1564](headroomlabs-ai#1564))
([96e1dfe](headroomlabs-ai@96e1dfe))
* **claude:** surface Remote Control proxy incompatibility
([headroomlabs-ai#1610](headroomlabs-ai#1610))
([4bf7f92](headroomlabs-ai@4bf7f92))
* **cli:** stop advertising unwired compression tuning env vars in
banner
([headroomlabs-ai#1634](headroomlabs-ai#1634))
([d5bf98d](headroomlabs-ai@d5bf98d))
* **codex:** avoid duplicate headroom provider config
([headroomlabs-ai#1431](headroomlabs-ai#1431))
([ddd4adf](headroomlabs-ai@ddd4adf))
* **compression:** reject lossy unmarked tool output in unit router path
([headroomlabs-ai#1479](headroomlabs-ai#1479))
([de24cd5](headroomlabs-ai@de24cd5))
* **cortex-code:** migrate to current Cortex REST API endpoints + add
e2e benchmarks
([headroomlabs-ai#1474](headroomlabs-ai#1474))
([f00ace6](headroomlabs-ai@f00ace6))
* **dashboard:** align token savings headline denominator
([headroomlabs-ai#1653](headroomlabs-ai#1653))
([646e705](headroomlabs-ai@646e705))
* **dashboard:** derive per-project setup URL from live origin
([headroomlabs-ai#1511](headroomlabs-ai#1511))
([e035aef](headroomlabs-ai@e035aef))
* **detection:** contain unidiff panic on orphaned +++ target line
([headroomlabs-ai#1548](headroomlabs-ai#1548))
([e386c09](headroomlabs-ai@e386c09))
* **evals:** CJK-aware F1 tokenization + token estimation
([headroomlabs-ai#1527](headroomlabs-ai#1527))
([99a8540](headroomlabs-ai@99a8540))
* **install:** close parent log fd in start_detached_agent
([headroomlabs-ai#1576](headroomlabs-ai#1576))
([816cb85](headroomlabs-ai@816cb85))
* **install:** use Windows-safe PID liveness probe in runtime_status
([headroomlabs-ai#1544](headroomlabs-ai#1544))
([headroomlabs-ai#1560](headroomlabs-ai#1560))
([6b227b9](headroomlabs-ai@6b227b9))
* **learn:** aggregate verbosity baselines across projects instead of
overwriting
([headroomlabs-ai#1288](headroomlabs-ai#1288))
([27a5468](headroomlabs-ai@27a5468))
* **mcp:** show lifetime totals and label rolling session scope in
headroom_stats
([headroomlabs-ai#1428](headroomlabs-ai#1428))
([1c0e152](headroomlabs-ai@1c0e152))
* **memory:** cap local embedder CPU thread oversubscription
([headroomlabs-ai#198](headroomlabs-ai#198))
([headroomlabs-ai#1559](headroomlabs-ai#1559))
([b84afbf](headroomlabs-ai@b84afbf))
* **memory:** singleflight LocalBackend init to stop cold-start races
([headroomlabs-ai#1691](headroomlabs-ai#1691))
([bec47a1](headroomlabs-ai@bec47a1))
* **openclaw:** detect uv-installed headroom binary in ~/.local/bin
([headroomlabs-ai#1459](headroomlabs-ai#1459))
([adaeb88](headroomlabs-ai@adaeb88))
* **opencode:** preserve custom OpenAI gateway paths
([headroomlabs-ai#1596](headroomlabs-ai#1596))
([c19347c](headroomlabs-ai@c19347c))
* **opencode:** route native providers + load transport plugin, fix
Serena context
([headroomlabs-ai#1573](headroomlabs-ai#1573))
([ad0034f](headroomlabs-ai@ad0034f))
* preserve anthropic passthrough tool order
([headroomlabs-ai#1427](headroomlabs-ai#1427))
([a932247](headroomlabs-ai@a932247))
* **proxy/auth:** match real Anthropic OAuth token prefix (sk-ant-oat)
([headroomlabs-ai#1672](headroomlabs-ai#1672))
([8cddf9b](headroomlabs-ai@8cddf9b))
* **proxy:** expose persistent savings metrics
([headroomlabs-ai#1647](headroomlabs-ai#1647))
([5fe4e7b](headroomlabs-ai@5fe4e7b))
* **proxy:** fail open when kompress saturation would exhaust
pre-upstream budget
([headroomlabs-ai#1430](headroomlabs-ai#1430))
([15ac650](headroomlabs-ai@15ac650))
* **proxy:** handle streaming CCR retrieval
([headroomlabs-ai#1451](headroomlabs-ai#1451))
([d337e3b](headroomlabs-ai@d337e3b))
* **proxy:** include system/tools/sampling in cache key
([headroomlabs-ai#1473](headroomlabs-ai#1473))
([312129a](headroomlabs-ai@312129a))
* **proxy:** preserve Responses passthrough bytes
([headroomlabs-ai#1598](headroomlabs-ai#1598))
([2a34a82](headroomlabs-ai@2a34a82))
* **proxy:** strip Codex lite header on the HTTP /responses path
([headroomlabs-ai#1663](headroomlabs-ai#1663))
([9fbd47b](headroomlabs-ai@9fbd47b))
* **proxy:** wire --compression-max-workers /
HEADROOM_COMPRESSION_MAX_WORKERS
([headroomlabs-ai#1632](headroomlabs-ai#1632))
([814ffa3](headroomlabs-ai@814ffa3))
* **savings:** count cache-read tokens in input cost estimate
([headroomlabs-ai#1429](headroomlabs-ai#1429))
([72ade37](headroomlabs-ai@72ade37))
* skip Magika backend on x86 CPUs without AVX2
([headroomlabs-ai#1162](headroomlabs-ai#1162))
([64783d8](headroomlabs-ai@64783d8))
* **transforms/content-router:** route grep/log output away from HTML
extractor
([headroomlabs-ai#1719](headroomlabs-ai#1719))
([0d18ef2](headroomlabs-ai@0d18ef2))
* **transforms:** bound native content detection with a Windows watchdog
([headroomlabs-ai#575](headroomlabs-ai#575))
([headroomlabs-ai#1563](headroomlabs-ai#1563))
([95abca3](headroomlabs-ai@95abca3))
* Vertex AI support for Claude Code with ANTHROPIC_VERTEX_BASE_URL
([headroomlabs-ai#1393](headroomlabs-ai#1393))
([cff7247](headroomlabs-ai@cff7247))
* **wrap:** detach the shared proxy on Windows so it survives an
ungraceful agent close
([headroomlabs-ai#1464](headroomlabs-ai#1464))
([6cba441](headroomlabs-ai@6cba441))
* **wrap:** preserve custom Vertex base URL
([headroomlabs-ai#1477](headroomlabs-ai#1477))
([75427bb](headroomlabs-ai@75427bb))
* **wrap:** remove rtk instructions from Codex AGENTS.md on unwrap
([headroomlabs-ai#1604](headroomlabs-ai#1604))
([c9d717c](headroomlabs-ai@c9d717c))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: ready for review Pull request body is complete and the author marked it ready for human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] headroom_stats MCP tool: surface lifetime totals + label window scope (currently shows only the rolling session)

2 participants