Skip to content

Octopus: stop flex dispatch promotion creating phantom slots (#4114); redact JWT in logs#4115

Merged
springfall2008 merged 2 commits into
mainfrom
fix/octopus_slots
Jun 22, 2026
Merged

Octopus: stop flex dispatch promotion creating phantom slots (#4114); redact JWT in logs#4115
springfall2008 merged 2 commits into
mainfrom
fix/octopus_slots

Conversation

@springfall2008

Copy link
Copy Markdown
Owner

Summary

Two Octopus Intelligent fixes:

1. Fix #4114 — phantom cheap slots from promoted flex dispatches

async_get_intelligent_devices previously promoted an in-progress flexPlannedDispatches entry into completed_dispatches once it had been live for >4 minutes ("so it's cached if withdrawn later"). But 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 (metered) dispatch — so PredBat planned/grid-charged against a cheap rate at times the customer was actually billed full peak rate (observed live on INTELLI-FIX).

Fix: remove the planned→completed promotion. Planned entries now stay only in the planned list and disappear naturally when Octopus withdraws them (matching Bottlecap Dave's HA integration). Genuine charging is unaffected — it is still cached via the metered completedDispatches feed (location="AT_HOME").

2. Redact JWT token in GraphQL logs + log responses

The GraphQL request log previously emitted the full headers dict, including Authorization: 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.py Test 8: an in-progress flex dispatch (started 10 min ago, ~0.367 kWh SMART, no location — the reported pattern) stays in planned and produces zero completed_dispatches.
  • test_octopus_logging.py (new): asserts the JWT token never appears in logs, <redacted> does, and the response body is logged.
  • Full octopus / ohme / multi-car IOG suites and run_pre_commit pass.

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 ephemeral started list, and extending octopus_intelligent_ignore_unplugged to completed dispatches were intentionally left out to keep this focused on the root cause; the existing fetch_previous_dispatch behaviour is covered by 15 deliberate tests. Happy to follow up if wanted.

🤖 Generated with Claude Code

… 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>
Copilot AI review requested due to automatic review settings June 22, 2026 18:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 flexPlannedDispatchescompleted_dispatches promotion logic to prevent withdrawn SMART/flex optimiser slots from becoming persistent “completed” cheap periods.
  • Redacted the Authorization JWT 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.

Comment thread apps/predbat/octopus.py Outdated
Comment thread apps/predbat/octopus.py
…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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment thread apps/predbat/octopus.py
Comment thread apps/predbat/octopus.py
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)
@springfall2008 springfall2008 merged commit f797e55 into main Jun 22, 2026
2 checks passed
@springfall2008 springfall2008 deleted the fix/octopus_slots branch June 22, 2026 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Octopus Intelligent: in-progress flexPlannedDispatches promoted to completed creates phantom cheap slots when EV unplugged

2 participants