Skip to content

Curtailment: Migrate active curtailment detail to keyed RPCs#444

Open
rongxin-liu wants to merge 14 commits into
mainfrom
rongxin/gh-387-keyed-active-curtailment-detail
Open

Curtailment: Migrate active curtailment detail to keyed RPCs#444
rongxin-liu wants to merge 14 commits into
mainfrom
rongxin/gh-387-keyed-active-curtailment-detail

Conversation

@rongxin-liu

@rongxin-liu rongxin-liu commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR moves active curtailment UI state from a single-active-event model to a list-plus-selected-detail model, so operators can see every active curtailment while the status card and edit flow stay focused on the selected event.

Behavior Changes

Area Before Now
Multiple active curtailments The UI effectively treated one active event as canonical, so another active scope could displace controls or history context. The active list is preserved for history/status rows, and the selected event is tracked independently for the status card and edit modal.
Starting new curtailments Opening a new plan was blocked while another curtailment was active. Operators can start a new plan while another curtailment is active, with stop/manage actions keyed to the correct event UUID.
Restoring/restored events A selected restoring or terminal event could disappear when another active event remained listed. Selected restoring/restored detail stays visible until dismissal, so completion/failure state is not lost during polling.
Active polling failures One failed detail request or transient read failure could stale or clear active controls. Detail hydration falls back to list summaries, read failures preserve cached stop/restore state, and only the selected event is hydrated in detail.
Large target sets Selected-event metrics could be based on only the first target page from GetCurtailmentEvent. Selected detail follows target pagination before committing detail, avoiding first-page-only active metrics.

Codebase Impact

  • Active curtailment cache now separates the active summary list from selected detail hydration, reducing polling fanout from every active event to the selected event.
  • Active event mutations are keyed: cancelled/failed responses remove or update only the affected event instead of clearing unrelated active curtailments.
  • useCurtailmentApi now exposes selected active-event hydration for secondary history-row management.
  • Curtailment history now tracks pending stop submissions per event, so concurrent stop requests keep each row disabled independently.
  • Tests now exercise the new list/detail RPC shape directly, including target pagination, partial detail failure fallback, selected terminal preservation, secondary active row actions, and multi-active stop races.

Verification

  • npm test -- --run protoFleet/api/activeCurtailmentData.test.ts protoFleet/api/useCurtailmentApi.test.ts protoFleet/components/PageHeader/useCurtailmentPillData.test.tsx protoFleet/features/energy/CurtailmentManagementPanel.test.tsx protoFleet/features/energy/CurtailmentHistory.test.tsx
  • npm run lint
  • npx tsc --noEmit

@github-actions github-actions Bot added javascript Pull requests that update javascript code client labels Jun 13, 2026
@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Note: This is an automated security-focused code review generated by Codex.
It should be used as a supplementary check alongside human review.
False positives are possible - use your judgment.

Scope summary

  • Reviewed pull request diff only (bc958f7679a2ec2468985133f3e3e621684c74f3...ec7affb6eb19d17617a7daace8c20bf3f5dfdd36, exact PR three-dot diff)
  • Model: gpt-5.5

💡 Click "edited" above to see previous reviews for this PR.


Review Summary

Overall Risk: MEDIUM

Findings

[MEDIUM] Active curtailment polling hydrates unbounded target pages

  • Category: Reliability
  • Location: client/src/protoFleet/api/activeCurtailmentData.ts:337
  • Description: The new active refresh path walks every nextTargetPageToken for the selected curtailment and accumulates all targets into memory. It guards repeated tokens, but there is no maximum page count, target count, or time budget. Because active curtailment refresh is used by polling surfaces, a large or malformed response can force repeated full-detail reads.
  • Impact: A large active curtailment can cause excessive RPC traffic, browser memory growth, and UI stalls. A backend pagination bug returning many unique tokens could keep the client fetching indefinitely until aborted.
  • Recommendation: Do not fully hydrate targets in background active polling. Use summaries/rollups for polling, fetch full targets only on explicit manage/detail actions, and add hard limits for max pages/targets plus a clear error when exceeded.

[MEDIUM] Stale manage-detail responses can open the wrong active curtailment

  • Category: Concurrency
  • Location: client/src/protoFleet/features/energy/CurtailmentManagementPanel.tsx:296
  • Description: openHistoryManageModal starts selectActiveCurtailment(event.id) without aborting any prior selection request or checking that the response still belongs to the latest requested row before calling setEditSession.
  • Impact: With multiple active curtailments, a slow response for row A can resolve after the operator has selected row B and overwrite the edit session. The modal can then submit updates or stop actions for the wrong curtailment event.
  • Recommendation: Track a selection request id or use an AbortController, pass the signal to selectActiveCurtailment, and ignore results that are not from the latest request. Also abort pending selection on unmount/modal close.

Notes

No SQL, backend authz, plugin, infrastructure, protobuf, or mining-pool address changes were present in the reviewed diff.


Generated by Codex Security Review |
Triggered by: @rongxin-liu |
Review workflow run

Preserve selected terminal events, bound detail hydration to the selected event, and isolate failed detail pages so multi-active polling stays reliable.
Keep cached active state through read failures and hydrate secondary active rows before management so operators retain correct stop and edit controls.
Keep protobuf test fixtures type-safe after adding target-page overrides for active detail hydration coverage.
@rongxin-liu rongxin-liu changed the title Migrate active curtailment detail to keyed RPCs Curtailment: Migrate active curtailment detail to keyed RPCs Jun 15, 2026
@rongxin-liu rongxin-liu marked this pull request as ready for review June 15, 2026 14:34
@rongxin-liu rongxin-liu requested a review from a team as a code owner June 15, 2026 14:34
Copilot AI review requested due to automatic review settings June 15, 2026 14:34

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ec7affb6eb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/api/useCurtailmentApi.ts
Comment thread client/src/protoFleet/features/energy/CurtailmentManagementPanel.tsx Outdated
Bound background detail hydration, render summary-only active rows without fake target metrics, and ignore stale manage-detail selections.
@rongxin-liu

rongxin-liu commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Active curtailment polling hydrates unbounded target pages

Addressed in dd395175: background active polling now requests only bounded event-level detail and drops partial target rows when pagination indicates the target list is incomplete. Full target pagination is reserved for explicit manage/detail selection and has a hard page cap with a clear error if exceeded.

Stale manage-detail responses can open the wrong active curtailment

Addressed in dd395175: secondary-row manage selection now aborts previous selection requests, passes the signal through the detail load, and ignores late responses unless they belong to the latest requested event. The same commit includes regression tests for the stale response race.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd39517504

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/components/PageHeader/useCurtailmentPillData.ts Outdated
Keep the header pill and active polling driven by non-terminal listed events when the selected curtailment is preserved as terminal.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6d1e0d56e6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Render summary-only active curtailment pill details without fake zero target metrics.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0d8aa2b9d9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Keep history row management aligned with updateable curtailment states so restoring rows cannot open an edit flow that the server rejects.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 30c411cb5f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/features/energy/CurtailmentManagementPanel.tsx Outdated
Prevent stale manage-detail responses from opening edit flows after an event transitions out of updateable states.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 10ecbabb2c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/protoFleet/api/useCurtailmentApi.ts Outdated
Let page-zero active injections filter each active event individually so non-selected active rows remain visible under matching filters.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c5388d27a7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Abort and invalidate in-flight history manage detail loads before opening the create curtailment flow.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d472712af4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +322 to +323
if (currentEvent.state === CurtailmentEventState.RESTORING) {
return events.length > 0 ? currentEvent : undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Drop vanished restoring events from active-only polls

When the selected event is RESTORING and ListActiveCurtailments no longer returns it while another curtailment is still active, this preserves the old event; getActiveCurtailmentSnapshotFromResponse then re-inserts that stale restoring event into snapshot.events. The page header's useCurtailmentPillData only runs refreshActiveCurtailmentData and never does the history reconciliation that can turn restoring into terminal, so in this multi-active scenario the pill can remain stuck on the vanished restoring curtailment and keep 3s polling instead of switching to the remaining active event.

Useful? React with 👍 / 👎.

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

Labels

client javascript Pull requests that update javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants