Skip to content

Send the client version in a FlexMeasures-Client-Version request header - #226

Merged
Flix6x merged 1 commit into
mainfrom
feat/client-version-header
Sep 16, 2026
Merged

Flix6x merged 1 commit into
mainfrom
feat/client-version-header

Conversation

@Flix6x

@Flix6x Flix6x commented Sep 16, 2026

Copy link
Copy Markdown
Member

Closes #212

Why

A FlexMeasures server can't tell which client version is calling it.
When the server changes a response in a way older clients misread, the only way to protect those clients is manual. The host sets FLEXMEASURES_LEGACY_JOB_RESPONSES_MAX_INCOMPATIBLE_CLIENT_VERSION and adds a version attribute to each affected asset.
A recent case: FlexMeasures ≥ v1.0.0 returns 202 while a scheduling job runs, and client 0.9.3 read that as the finished schedule. The Home Assistant integration then failed with KeyError: 'values' (see FlexMeasures/flexmeasures-ha-integration#31).

With the version in every request, the server can make that decision per request, with no attributes to set.

What

  • Every request now sends FlexMeasures-Client-Version: <flexmeasures_client.__version__>. It's added in get_headers(), so it covers:
    • unauthenticated requests (requestAuthToken, get_versions), so the server knows the version from the first request;
    • authenticated API requests;
    • file uploads, which drop only Content-Type from those headers.
  • The header name lives in constants.CLIENT_VERSION_HEADER.

Why a custom header rather than User-Agent

  • It mirrors the server's FlexMeasures-Version response header.
  • User-Agent belongs to the calling app. Home Assistant's shared session already sets it to HomeAssistant/… aiohttp/… Python/…. Overwriting that would hide the app from server logs, and merging our token in would mean editing a header the client doesn't own.
  • A dedicated header holds just the version, so the server can compare versions without parsing the free-form User-Agent list.

Adding a flexmeasures-client/<version> token to User-Agent for logs and proxies could be a separate change.

Tests

  • New test_every_request_sends_the_client_version: runs a token request, a versions request, an authenticated GET and a file upload, and checks that all four send the header.
  • The 16 existing tests that compare full request headers now include the new header.
  • Checked that the tests can fail: with the header removed from get_headers(), 17 tests fail, including the new one. With it restored, the whole non-S2 suite passes (224 tests).
  • All pre-commit hooks pass (isort, black, flake8, mypy).

Follow-up on the FlexMeasures side (not in this PR)

  • use_legacy_job_responses() could read this header before checking asset attributes.
  • Clients up to 0.9.5 never send the header, so a missing header must mean "unknown", not "old".
  • Optionally, store the last-seen client version on the user, to see which client versions are in use.

🤖 Generated with Claude Code

https://claude.ai/code/session_019heS4SVj8UqZ8BiMqDvoXj

…t header

Every request now carries the client version, including the unauthenticated token and versions requests and file uploads, so the server knows it from the very first request.
The name mirrors the server's FlexMeasures-Version response header.
This lets a FlexMeasures server adapt responses to what a client supports, instead of relying on a manually set asset attribute.

Existing tests that assert the exact request headers now expect the new header.

Closes #212

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019heS4SVj8UqZ8BiMqDvoXj
Signed-off-by: F.N. Claessen <claessen@seita.nl>
@Flix6x Flix6x added the enhancement New feature or request label Sep 16, 2026
@Flix6x Flix6x self-assigned this Sep 16, 2026
@Flix6x
Flix6x merged commit 1b75125 into main Sep 16, 2026
17 checks passed
@Flix6x
Flix6x deleted the feat/client-version-header branch September 16, 2026 18:29
@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 35134394770

Coverage increased (+0.007%) to 96.831%

Details

  • Coverage increased (+0.007%) from the base build.
  • Patch coverage: 4 of 4 lines across 2 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 852
Covered Lines: 825
Line Coverage: 96.83%
Coverage Strength: 9.68 hits per line

💛 - Coveralls

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Send the client version in the header

2 participants