Skip to content

perf: Optimize PMO StreamHub for O(1) incremental updates (P012)#1979

Merged
DaveSkender merged 6 commits intov3from
copilot/implement-task-p012
Feb 28, 2026
Merged

perf: Optimize PMO StreamHub for O(1) incremental updates (P012)#1979
DaveSkender merged 6 commits intov3from
copilot/implement-task-p012

Conversation

Copy link
Contributor

Copilot AI commented Feb 28, 2026

  • Original P012 optimization: O(1) incremental PMO StreamHub
  • Adapt to PR refactor: Centralize RollbackState with index-based signature (P011) #1978 changes: replace RollbackState(DateTime) with RollbackState(int restoreIndex)
  • Re-add PruneState(DateTime) override for cache pruning alignment
  • Fix CI: resolve build failure (CS0115)
  • Verify all PMO tests pass (27/27)
  • Run full test suite (2392 passed, 0 failed)
  • Mark P012 complete in streaming plan

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI self-assigned this Feb 28, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 28, 2026

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI changed the title [WIP] Implement task P012 from streaming plan perf: Optimize PMO StreamHub for O(1) incremental updates (P012) Feb 28, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/m-r/Pmo/Pmo.StreamHub.cs`:
- Around line 156-160: RollbackState currently clears state then bails when
ProviderCache.IndexGte(timestamp) returns <= 0, which lets histories stay
cleared if IndexGte returns -1; change RollbackState to handle the -1 case and
replay the cache instead of leaving state empty: after computing targetIndex =
ProviderCache.IndexGte(timestamp) treat -1 as "replay everything" (e.g. set
targetIndex = ProviderCache.Count), then clear state and replay cached items
from index 0 up to targetIndex - 1 (exclusive) to rebuild histories; reference
the RollbackState method, ProviderCache.IndexGte, targetIndex and the replay
loop when implementing this fix.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e32d09 and 8198480.

📒 Files selected for processing (2)
  • docs/plans/streaming-indicators.plan.md
  • src/m-r/Pmo/Pmo.StreamHub.cs

@DaveSkender DaveSkender temporarily deployed to stockindicators.dev February 28, 2026 19:08 — with GitHub Actions Inactive
@DaveSkender DaveSkender temporarily deployed to stockindicators.dev February 28, 2026 19:43 — with GitHub Actions Inactive
@DaveSkender DaveSkender temporarily deployed to stockindicators.dev February 28, 2026 23:10 — with GitHub Actions Inactive
@DaveSkender
Copy link
Owner

@copilot In the base branch (now merged into this branch) we made a fairly significant set of changes to how rollbacks occur (see PR #1978). Consider if this impacts how you implement the fix for this solution. In any case, resolve the CI check failures and ensure a clean code completion with no lint, build, or test failures.

Copy link
Contributor Author

Copilot AI commented Feb 28, 2026

@copilot In the base branch (now merged into this branch) we made a fairly significant set of changes to how rollbacks occur (see PR #1978). Consider if this impacts how you implement...

Adapted to the new RollbackState(int restoreIndex) signature from PR #1978. The old RollbackState(DateTime timestamp) override was replaced — now uses restoreIndex directly (replay 0..restoreIndex inclusive), and PruneState(DateTime) is restored as a separate override for cache pruning. Build, lint, and all 2392 tests pass (commit d14fbf1).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/m-r/Pmo/Pmo.StreamHub.cs (1)

149-196: RollbackState correctly adapted to new int restoreIndex API.

The implementation properly:

  • Clears state before replay (lines 152-154)
  • Handles negative index sentinel by early return (line 156-159)
  • Replays items 0 through restoreIndex inclusive (line 164) to rebuild EMA state

The past review comment about IndexGte == -1 handling is no longer applicable since the API changed from RollbackState(DateTime timestamp) to RollbackState(int restoreIndex) per PR #1978 — the framework now passes the index directly.

Consider extracting the ROC/ROC EMA calculation (lines 169-194) into a private helper method to eliminate duplication with ToIndicator (lines 68-94). This would improve maintainability if the calculation logic ever needs adjustment.

♻️ Optional refactor to reduce duplication
+    private void ComputeRocState(int index)
+    {
+        double currVal = ProviderCache[index].Value;
+        double prevVal = index > 0 ? ProviderCache[index - 1].Value : double.NaN;
+
+        double roc = prevVal == 0 ? double.NaN : 100 * ((currVal / prevVal) - 1);
+        _rocHistory.Add(roc);
+
+        double rocEma;
+        if (double.IsNaN(_prevRocEma) && index >= TimePeriods)
+        {
+            double sum = 0;
+            for (int p = index - TimePeriods + 1; p <= index; p++)
+            {
+                sum += _rocHistory[p];
+            }
+            rocEma = sum / TimePeriods;
+        }
+        else if (!double.IsNaN(_prevRocEma))
+        {
+            rocEma = _prevRocEma + (smoothingConstant2 * (roc - _prevRocEma));
+        }
+        else
+        {
+            rocEma = double.NaN;
+        }
+
+        _prevRocEma = rocEma;
+        _rocEmaHistory.Add(rocEma * 10);
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/m-r/Pmo/Pmo.StreamHub.cs` around lines 149 - 196, RollbackState correctly
replays EMA state but duplicates the ROC/ROC-EMA logic used in ToIndicator;
extract the shared computation into a private helper (e.g., ComputeRocAndEma or
UpdateRocEma) that accepts the current index and the ProviderCache/values (or
just currVal/prevVal) and returns/updates roc and rocEma (using TimePeriods,
smoothingConstant2, _prevRocEma, _rocHistory, _rocEmaHistory as needed); replace
the duplicated loop body in RollbackState and the corresponding block in
ToIndicator with calls to this helper so both use the same logic and avoid
maintenance drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/m-r/Pmo/Pmo.StreamHub.cs`:
- Around line 149-196: RollbackState correctly replays EMA state but duplicates
the ROC/ROC-EMA logic used in ToIndicator; extract the shared computation into a
private helper (e.g., ComputeRocAndEma or UpdateRocEma) that accepts the current
index and the ProviderCache/values (or just currVal/prevVal) and returns/updates
roc and rocEma (using TimePeriods, smoothingConstant2, _prevRocEma, _rocHistory,
_rocEmaHistory as needed); replace the duplicated loop body in RollbackState and
the corresponding block in ToIndicator with calls to this helper so both use the
same logic and avoid maintenance drift.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55ea5e1 and d14fbf1.

📒 Files selected for processing (2)
  • docs/plans/streaming-indicators.plan.md
  • src/m-r/Pmo/Pmo.StreamHub.cs

@DaveSkender DaveSkender enabled auto-merge (squash) February 28, 2026 23:41
@DaveSkender DaveSkender merged commit d7632df into v3 Feb 28, 2026
13 checks passed
@DaveSkender DaveSkender deleted the copilot/implement-task-p012 branch February 28, 2026 23:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

2 participants