Octopus: stop flex dispatch promotion creating phantom slots (#4114); redact JWT in logs#4115
Merged
Conversation
… redact JWT in logs Fix #4114: async_get_intelligent_devices no longer promotes in-progress flexPlannedDispatches entries into completed_dispatches. flexPlannedDispatches is Octopus's optimiser schedule and includes plug-independent SMART grid-flex events that Octopus routinely withdraws on its next re-plan. Promoting them immortalised provisional slots as permanent cheap "completed" slots with no matching real dispatch, driving phantom cheap planning/grid-charging at full-peak-rate times. Planned entries now stay only in the planned list and disappear naturally when withdrawn; genuine charging is still cached via the metered completedDispatches feed (location=AT_HOME). Also redact the JWT token from the GraphQL request log and add logging of GraphQL response bodies for diagnostics. The token-refresh response (which carries the JWT) uses a separate path and is not logged. Adds regression tests for both changes and bumps version to v8.41.4. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR addresses two Octopus Intelligent issues in PredBat: (1) preventing “phantom” cheap slots caused by promoting provisional flexPlannedDispatches entries into completed_dispatches (issue #4114), and (2) improving GraphQL diagnostics while ensuring JWTs are not leaked to logs. It also bumps the app version and extends the unit test suite to cover the new behaviors.
Changes:
- Removed the
flexPlannedDispatches→completed_dispatchespromotion logic to prevent withdrawn SMART/flex optimiser slots from becoming persistent “completed” cheap periods. - Redacted the
AuthorizationJWT in GraphQL request logging and added GraphQL response logging for troubleshooting. - Added/updated unit tests covering the non-promotion behavior and JWT redaction/response logging; bumped version to
v8.41.4.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
apps/predbat/octopus.py |
Stops promoting in-progress flex planned dispatches to completed; redacts JWT in request logs; logs GraphQL responses. |
apps/predbat/tests/test_octopus_intelligent_devices.py |
Adds regression coverage for issue #4114 (in-progress flex dispatch must remain planned only). |
apps/predbat/tests/test_octopus_logging.py |
New tests to assert JWT redaction and that GraphQL responses are logged. |
apps/predbat/unit_test.py |
Registers the new Octopus logging test in the test runner. |
apps/predbat/predbat.py |
Version bump to v8.41.4. |
…w feedback) Removing the planned->completed promotion (issue #4114) also removed the trimming of an already-started slot. decode_octopus_slot does not trim a started slot to now when charge_in_kwh > 0, so an in-progress flex dispatch left in planned with a past start and full charge_in_kwh would double-count the already-delivered energy and inflate predicted car SoC/cost. Keep the dispatch in planned_dispatches (so it still vanishes when Octopus withdraws it), but if it is in progress advance its start to now and scale charge_in_kwh to the remaining portion of the slot. Extends Test 8 to assert the trim/scale and adds Test 9 (future slot untouched). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment on lines
+1757
to
+1767
| start_date_time = parse_date_time(start) | ||
| end_date_time = parse_date_time(end) | ||
| if start_date_time and end_date_time and start_date_time < self.now_utc_exact < end_date_time: | ||
| total_minutes = (end_date_time - start_date_time).total_seconds() / 60 | ||
| remaining_minutes = (end_date_time - self.now_utc_exact).total_seconds() / 60 | ||
| if total_minutes > 0: | ||
| if delta is not None: | ||
| delta = dp4(delta * remaining_minutes / total_minutes) | ||
| dispatch["charge_in_kwh"] = delta | ||
| dispatch["start"] = self.now_utc_exact.strftime(DATE_TIME_STR_FORMAT) | ||
| planned.append(dispatch) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two Octopus Intelligent fixes:
1. Fix #4114 — phantom cheap slots from promoted flex dispatches
async_get_intelligent_devicespreviously promoted an in-progressflexPlannedDispatchesentry intocompleted_dispatchesonce it had been live for >4 minutes ("so it's cached if withdrawn later"). ButflexPlannedDispatchesis Octopus's optimiser schedule and includes plug-independentSMARTgrid-flex events that Octopus routinely withdraws on its next re-plan. Promoting them immortalised provisional slots as permanent cheap "completed" slots with no matching real (metered) dispatch — so PredBat planned/grid-charged against a cheap rate at times the customer was actually billed full peak rate (observed live onINTELLI-FIX).Fix: remove the planned→completed promotion. Planned entries now stay only in the
plannedlist and disappear naturally when Octopus withdraws them (matching Bottlecap Dave's HA integration). Genuine charging is unaffected — it is still cached via the meteredcompletedDispatchesfeed (location="AT_HOME").2. Redact JWT token in GraphQL logs + log responses
The GraphQL request log previously emitted the full
headersdict, includingAuthorization: JWT <token>. The Authorization value is now redacted. Also added logging of GraphQL response bodies for diagnostics. The token-refresh response (which carries the JWT) uses a separate code path and is not logged.Tests
test_octopus_intelligent_devices.pyTest 8: an in-progress flex dispatch (started 10 min ago, ~0.367 kWhSMART, no location — the reported pattern) stays inplannedand produces zerocompleted_dispatches.test_octopus_logging.py(new): asserts the JWT token never appears in logs,<redacted>does, and the response body is logged.run_pre_commitpass.Version bumped to v8.41.4.
Deferred (optional items from #4114)
Dedup completed by
(start, end), a rolling 2-days-from-midnight prune window, an ephemeralstartedlist, and extendingoctopus_intelligent_ignore_unpluggedto completed dispatches were intentionally left out to keep this focused on the root cause; the existingfetch_previous_dispatchbehaviour is covered by 15 deliberate tests. Happy to follow up if wanted.🤖 Generated with Claude Code