refactor: Centralize RollbackState with index-based signature (P011)#1978
refactor: Centralize RollbackState with index-based signature (P011)#1978DaveSkender merged 5 commits intov3from
Conversation
Co-authored-by: DaveSkender <[email protected]>
|
Important Review skippedBot user detected. To trigger a single review, invoke the You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe pull request updates the streaming indicators plan to mark task P011 as completed and modifies the AdlHub class to track incremental ADL state. A new private field stores the previous ADL value, which replaces the previous cache-based increment calculation in the ToIndicator method. The RollbackState override restores the stored ADL value to the state before the rollback timestamp, or resets it to zero when the rollback point is at or before the start of the data. Possibly related PRs
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. Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
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/a-d/Adl/Adl.StreamHub.cs`:
- Around line 50-58: The RollbackState implementation incorrectly treats
targetIndex == -1 the same as <= 0 and resets _previousAdl to 0, losing running
state; update RollbackState so it handles the IndexGte == -1 case explicitly: if
targetIndex == -1, set _previousAdl from the last cached entry
(Cache.Last().Adl) if Cache has entries (or 0 if empty), otherwise keep the
existing _previousAdl when targetIndex < 0 is meant to mean “before any provider
items”; keep the existing restore logic for targetIndex > 0 (use restoreIndex =
targetIndex - 1 and Cache[restoreIndex].Adl). Ensure you reference and update
the code paths that use targetIndex, _previousAdl, Cache and the RollbackState
method.
Signed-off-by: Dave Skender <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
src/s-z/VolatilityStop/VolatilityStop.StreamHub.cs (1)
198-202:⚠️ Potential issue | 🟡 MinorUpdate XML documentation to reflect parameter change.
The summary references "timestamp" but the parameter is now
int restoreIndex. This should be updated for consistency.📝 Proposed fix
/// <summary> -/// Restores the Volatility Stop state up to the specified timestamp. +/// Restores the Volatility Stop state up to the specified index. /// </summary> /// <inheritdoc/> protected override void RollbackState(int restoreIndex)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/s-z/VolatilityStop/VolatilityStop.StreamHub.cs` around lines 198 - 202, The XML doc comment for VolatilityStop.StreamHub.cs's protected override method RollbackState(int restoreIndex) incorrectly mentions "timestamp"; update the <summary> and any related XML tags to describe restoring state up to the provided restoreIndex parameter (or simply "Restores the Volatility Stop state to the specified restoreIndex") and update the <param> tag name/details to match the parameter restoreIndex so the documentation is consistent with the method signature.src/m-r/MaEnvelopes/MaEnvelopes.StreamHub.cs (1)
367-385:⚠️ Potential issue | 🟠 MajorRollback state reset is incomplete for DEMA/TEMA continuity.
On Line 369,
RollbackState(int restoreIndex)clears EMA layer fields but does not reconstruct them torestoreIndex - 1. After late edits, recalculation can resume withCache[index - 1].Centerlinepresent whilelastEma*is stillNaN, which can produce incorrect DEMA/TEMA values. Please replay EMA layers up torestoreIndex - 1(exclusive rollback point) during rollback before recomputation starts.Suggested direction
protected override void RollbackState(int restoreIndex) { - if (restoreIndex >= lookbackPeriods) - { - if (movingAverageType == MaType.DEMA) - { - lastEma1 = lastEma2 = double.NaN; - } - else if (movingAverageType == MaType.TEMA) - { - lastEma3 = lastEma4 = lastEma5 = double.NaN; - } - } - else - { - lastEma1 = lastEma2 = lastEma3 = lastEma4 = lastEma5 = double.NaN; - } + lastEma1 = lastEma2 = lastEma3 = lastEma4 = lastEma5 = double.NaN; + if (restoreIndex <= 0) return; + if (movingAverageType is not MaType.DEMA and not MaType.TEMA) return; + + // replay state to restoreIndex - 1 so incremental updates restart from valid EMA layers + ReplayEmaLayerState(restoreIndex - 1); }Based on learnings: Applies to
src/**/*.StreamHub.cs: OverrideRollbackState(...)when maintaining stateful fields in StreamHub indicators, replaying up totargetIndex - 1(exclusive).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/m-r/MaEnvelopes/MaEnvelopes.StreamHub.cs` around lines 367 - 385, RollbackState currently clears EMA layer fields (lastEma1..lastEma5) which leaves them NaN when Cache[restoreIndex - 1].Centerline exists; fix by replaying EMA layers up to the index before the rollback point: inside RollbackState, when restoreIndex < lookbackPeriods (or generally when cached centerlines exist), iterate from the earliest cached index needed up to restoreIndex - 1 and update the EMA chain using the same per-tick EMA update logic so lastEma1/2/3/4/5 reflect the state at restoreIndex - 1; keep the existing branch for movingAverageType == MaType.DEMA and MaType.TEMA to replay only the required EMA layers, and only set fields to double.NaN when there is no cached history to reconstruct.src/s-z/Trix/Trix.StreamHub.cs (1)
92-98:⚠️ Potential issue | 🟠 MajorRollback boundary is off for seeded TRIX state and can produce incorrect post-rollback values.
At Line 92,
restoreIndex >= LookbackPeriodsskips restoration when the preserved point is exactly the seed index (LookbackPeriods - 1). The next processed item then reinitializes instead of continuing incrementally.Based on learnings: "In StreamHub RollbackState implementations, boundary condition checks vary by algorithm requirements: patterns that need prior period values ... use stricter boundary checks."Proposed fix
- if (restoreIndex >= LookbackPeriods) + if (restoreIndex >= LookbackPeriods - 1) { TrixResult prior = Cache[restoreIndex]; lastEma1 = prior.Ema1; lastEma2 = prior.Ema2; - lastEma3 = prior.Ema3 ?? double.NaN; + // At seed boundary, Ema3 output can be null while internal EMA state exists. + lastEma3 = prior.Ema3 ?? prior.Ema2; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/s-z/Trix/Trix.StreamHub.cs` around lines 92 - 98, The rollback boundary skips restoring the seeded TRIX state when restoreIndex equals the seed index (LookbackPeriods - 1); change the guard in the rollback block from "restoreIndex >= LookbackPeriods" to "restoreIndex >= LookbackPeriods - 1" so the code restores the cached TrixResult for that seed index (use Cache[restoreIndex] to set lastEma1/lastEma2/lastEma3 as before) and preserve incremental continuation instead of reinitializing; update the condition around restoreIndex, LookbackPeriods, Cache, and TrixResult accordingly.src/a-d/ConnorsRsi/ConnorsRsi.StreamHub.cs (1)
271-276:⚠️ Potential issue | 🟠 MajorRollback replay misses the index-0 gain seed used in live processing.
ToIndicator()seedsgainBufferat index 0, butRollbackState()does not. That can shift the percent-rank window after early rollbacks and produce mismatched results.🔧 Suggested fix
if (i == 0) { prevValue = value; streak = 0; streakBuffer.Add(0); + + // Keep rollback state consistent with ToIndicator() at index 0 + double gain = double.IsNaN(value) || value <= 0 + ? double.NaN + : 0d; + gainBuffer.Enqueue(gain); } else { // Calculate streak if (double.IsNaN(value) || double.IsNaN(prevValue)) @@ gainBuffer.Enqueue(gain); if (gainBuffer.Count > RankPeriods + 1) { gainBuffer.Dequeue(); }Based on learnings: streaming hubs should rebuild from mutation points and realign with full-history Series results after inserts/removals/revisions.
Also applies to: 360-369
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/a-d/ConnorsRsi/ConnorsRsi.StreamHub.cs` around lines 271 - 276, RollbackState() currently fails to seed the index-0 gain used by ToIndicator(), causing window alignment drift after early rollbacks; update RollbackState() to initialize the gainBuffer (and any related streakBuffer/gain seed logic) at index 0 exactly as ToIndicator() does so the percent-rank window matches live processing, and apply the same fix to the related block around the 360-369 region to ensure rebuilds from mutation points realign full-history Series results after inserts/removals/revisions.src/s-z/Slope/Slope.StreamHub.cs (1)
142-153:⚠️ Potential issue | 🟠 MajorRestore partial buffer even before warmup threshold.
Line [142] exits when
restoreIndex < LookbackPeriods - 1, which leavesbufferempty. After rollback on early history edits, replay resumes atrestoreIndex + 1, so the first calculable window is built from too few points and yields incorrect slope/intercept (downstream EPMA is affected too).💡 Suggested fix
- if (restoreIndex < LookbackPeriods - 1) + if (restoreIndex < 0) { return; } // Rebuild buffer from cache up to restoreIndex int startIdx = Math.Max(0, restoreIndex - LookbackPeriods + 1); for (int p = startIdx; p <= restoreIndex; p++) { - buffer.Enqueue(ProviderCache[p].Value); + buffer.Update(LookbackPeriods, ProviderCache[p].Value); }Based on learnings: when late inserts/removals occur, StreamHub state must rebuild from provider cache so results realign with full-series output.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/s-z/Slope/Slope.StreamHub.cs` around lines 142 - 153, The early return when restoreIndex < LookbackPeriods - 1 leaves buffer empty after a rollback; change the logic in Slope.StreamHub so you always rebuild the buffer from ProviderCache up to restoreIndex (compute startIdx = Math.Max(0, restoreIndex - LookbackPeriods + 1) and enqueue ProviderCache[p].Value for p in startIdx..restoreIndex) instead of returning early—this ensures the partial window is reconstructed before replay resumes so slope/intercept calculations align with full-series output.
🧹 Nitpick comments (5)
src/e-k/FisherTransform/FisherTransform.StreamHub.cs (1)
118-123: Update rollback XML docs to match index semantics.The summary still describes a timestamp-based restore, but the method now takes
restoreIndex. Please update wording around Line [119]-Line [123] to avoid misuse later.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/e-k/FisherTransform/FisherTransform.StreamHub.cs` around lines 118 - 123, Update the XML documentation for the RollbackState method to reflect that it restores state based on an integer restoreIndex rather than a timestamp: change the summary and remarks to say it restores the rolling window and xv state up to the specified restoreIndex, and that it clears and rebuilds rolling windows and the xv array from ProviderCache for Add/Remove operations using the given index; ensure the <inheritdoc/> and method signature protected override void RollbackState(int restoreIndex) remain unchanged and reference the parameter name restoreIndex in the docs if param tags are present.src/s-z/Vwap/Vwap.StreamHub.cs (1)
75-79: Update the XML summary to match the new rollback parameter.The summary still references a timestamp, but the method now restores by cache index.
✏️ Suggested doc update
- /// Restores the cumulative state up to the specified timestamp. + /// Restores the cumulative state up to the specified cache index.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/s-z/Vwap/Vwap.StreamHub.cs` around lines 75 - 79, Update the XML summary for the RollbackState method to describe that it restores the cumulative state up to the provided cache index rather than a timestamp; reference the method name RollbackState and the parameter restoreIndex in the summary and param documentation so the docs match the new rollback-by-index behavior.src/a-d/Cci/Cci.StreamHub.cs (1)
44-49: Align the rollback XML docs with index-based semantics.The summary still says “timestamp,” but rollback now restores by index.
✏️ Suggested doc update
- /// Restores the CciList state up to the specified timestamp. + /// Restores the CciList state up to the specified cache index.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/a-d/Cci/Cci.StreamHub.cs` around lines 44 - 49, Update the XML documentation on the RollbackState method to reflect index-based semantics: change the <summary> to say it "Restores the CciList state up to the specified index" (not "timestamp"), and adjust the explanatory sentence to mention that it clears and rebuilds _cciList from ProviderCache using the provided restoreIndex for Add/Remove operations; ensure the <inheritdoc/> or param references match the restoreIndex parameter name.src/s-z/Vortex/Vortex.StreamHub.cs (2)
123-136: Remove redundant conditional check.The condition
if (restoreIndex >= 0)on line 129 is always true because the method already returns early whenrestoreIndex < 0at line 123.♻️ Suggested simplification
if (restoreIndex < 0) { return; } // Process first quote to initialize state - if (restoreIndex >= 0) - { - IQuote firstQuote = ProviderCache[0]; - _prevHigh = (double)firstQuote.High; - _prevLow = (double)firstQuote.Low; - _prevClose = (double)firstQuote.Close; - _isInitialized = true; - } + IQuote firstQuote = ProviderCache[0]; + _prevHigh = (double)firstQuote.High; + _prevLow = (double)firstQuote.Low; + _prevClose = (double)firstQuote.Close; + _isInitialized = true;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/s-z/Vortex/Vortex.StreamHub.cs` around lines 123 - 136, The check "if (restoreIndex >= 0)" is redundant because the method already returns when restoreIndex < 0; remove that conditional and directly initialize the first quote: read ProviderCache[0] into an IQuote (firstQuote) and assign _prevHigh, _prevLow, _prevClose from firstQuote.High/Low/Close and set _isInitialized = true (keep the same symbols: restoreIndex, ProviderCache, IQuote firstQuote, _prevHigh, _prevLow, _prevClose, _isInitialized) so the initialization block runs unconditionally after the early return.
162-169: Remove redundant conditional check.Same issue:
if (restoreIndex >= 0)at line 163 is always true after the early return at line 123.♻️ Suggested simplification
// Update prev values to the last processed quote - if (restoreIndex >= 0) - { - IQuote lastQuote = ProviderCache[restoreIndex]; - _prevHigh = (double)lastQuote.High; - _prevLow = (double)lastQuote.Low; - _prevClose = (double)lastQuote.Close; - } + IQuote lastQuote = ProviderCache[restoreIndex]; + _prevHigh = (double)lastQuote.High; + _prevLow = (double)lastQuote.Low; + _prevClose = (double)lastQuote.Close;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/s-z/Vortex/Vortex.StreamHub.cs` around lines 162 - 169, The if (restoreIndex >= 0) check is redundant because an earlier early-return guarantees restoreIndex is non-negative; remove the conditional and directly update prev values by retrieving IQuote lastQuote = ProviderCache[restoreIndex] and assigning _prevHigh, _prevLow, and _prevClose from lastQuote.High/Low/Close so the code always executes that update without the unnecessary guard.
🤖 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/_common/StreamHub/StreamHub.cs`:
- Around line 367-377: Add a temporary compatibility shim for the changed
RollbackState signature: keep a protected virtual RollbackState(int
restoreIndex) overload marked with [Obsolete("Migration: override
RollbackState(...new signature...) instead. This shim will be removed in a
future release.")] that forwards to the new RollbackState implementation (call
the new overload with appropriate default values or map restoreIndex to the new
parameters) so existing subclasses continue to compile while they migrate;
update XML docs on the obsolete method to point to the new signature and ensure
the new RollbackState(newSignature) is the canonical implementation.
In `@src/a-d/Dema/Dema.StreamHub.cs`:
- Around line 72-75: The rollback boundary is off-by-one: change the condition
on restoreIndex so you include the case where restoreIndex == LookbackPeriods -
1 and restore prior EMA state; update the block that reads from
Cache[restoreIndex] (DemaResult prior = Cache[restoreIndex]) to assign both
lastEma1 and lastEma2 from prior (e.g., lastEma1 = prior.Ema1; lastEma2 =
prior.Ema2) and use the adjusted check (restoreIndex >= LookbackPeriods - 1) so
subsequent DEMA recalculation after rollback has the needed prior-period EMAs.
In `@src/s-z/Smi/Smi.StreamHub.cs`:
- Around line 169-172: The early return when restoreIndex < LookbackPeriods - 1
causes _highWindow and _lowWindow (cleared just above) to remain empty after a
warmup rollback; instead, remove or change that return so the rollback path
always repopulates the rolling windows (_highWindow, _lowWindow) from the
available warmup/history data and only skip invoking CalculateSmi() during
warmup. Concretely: in the method in Smi.StreamHub.cs where restoreIndex and
LookbackPeriods are checked, replace the early return with logic that
rebuilds/populates the windows using the existing buffer/history and then gates
the call to CalculateSmi() (e.g., if restoreIndex >= LookbackPeriods - 1 then
call CalculateSmi(), otherwise skip it). Ensure you reference and refill
_highWindow and _lowWindow consistently so subsequent updates work correctly
after rollback.
---
Outside diff comments:
In `@src/a-d/ConnorsRsi/ConnorsRsi.StreamHub.cs`:
- Around line 271-276: RollbackState() currently fails to seed the index-0 gain
used by ToIndicator(), causing window alignment drift after early rollbacks;
update RollbackState() to initialize the gainBuffer (and any related
streakBuffer/gain seed logic) at index 0 exactly as ToIndicator() does so the
percent-rank window matches live processing, and apply the same fix to the
related block around the 360-369 region to ensure rebuilds from mutation points
realign full-history Series results after inserts/removals/revisions.
In `@src/m-r/MaEnvelopes/MaEnvelopes.StreamHub.cs`:
- Around line 367-385: RollbackState currently clears EMA layer fields
(lastEma1..lastEma5) which leaves them NaN when Cache[restoreIndex -
1].Centerline exists; fix by replaying EMA layers up to the index before the
rollback point: inside RollbackState, when restoreIndex < lookbackPeriods (or
generally when cached centerlines exist), iterate from the earliest cached index
needed up to restoreIndex - 1 and update the EMA chain using the same per-tick
EMA update logic so lastEma1/2/3/4/5 reflect the state at restoreIndex - 1; keep
the existing branch for movingAverageType == MaType.DEMA and MaType.TEMA to
replay only the required EMA layers, and only set fields to double.NaN when
there is no cached history to reconstruct.
In `@src/s-z/Slope/Slope.StreamHub.cs`:
- Around line 142-153: The early return when restoreIndex < LookbackPeriods - 1
leaves buffer empty after a rollback; change the logic in Slope.StreamHub so you
always rebuild the buffer from ProviderCache up to restoreIndex (compute
startIdx = Math.Max(0, restoreIndex - LookbackPeriods + 1) and enqueue
ProviderCache[p].Value for p in startIdx..restoreIndex) instead of returning
early—this ensures the partial window is reconstructed before replay resumes so
slope/intercept calculations align with full-series output.
In `@src/s-z/Trix/Trix.StreamHub.cs`:
- Around line 92-98: The rollback boundary skips restoring the seeded TRIX state
when restoreIndex equals the seed index (LookbackPeriods - 1); change the guard
in the rollback block from "restoreIndex >= LookbackPeriods" to "restoreIndex >=
LookbackPeriods - 1" so the code restores the cached TrixResult for that seed
index (use Cache[restoreIndex] to set lastEma1/lastEma2/lastEma3 as before) and
preserve incremental continuation instead of reinitializing; update the
condition around restoreIndex, LookbackPeriods, Cache, and TrixResult
accordingly.
In `@src/s-z/VolatilityStop/VolatilityStop.StreamHub.cs`:
- Around line 198-202: The XML doc comment for VolatilityStop.StreamHub.cs's
protected override method RollbackState(int restoreIndex) incorrectly mentions
"timestamp"; update the <summary> and any related XML tags to describe restoring
state up to the provided restoreIndex parameter (or simply "Restores the
Volatility Stop state to the specified restoreIndex") and update the <param> tag
name/details to match the parameter restoreIndex so the documentation is
consistent with the method signature.
---
Nitpick comments:
In `@src/a-d/Cci/Cci.StreamHub.cs`:
- Around line 44-49: Update the XML documentation on the RollbackState method to
reflect index-based semantics: change the <summary> to say it "Restores the
CciList state up to the specified index" (not "timestamp"), and adjust the
explanatory sentence to mention that it clears and rebuilds _cciList from
ProviderCache using the provided restoreIndex for Add/Remove operations; ensure
the <inheritdoc/> or param references match the restoreIndex parameter name.
In `@src/e-k/FisherTransform/FisherTransform.StreamHub.cs`:
- Around line 118-123: Update the XML documentation for the RollbackState method
to reflect that it restores state based on an integer restoreIndex rather than a
timestamp: change the summary and remarks to say it restores the rolling window
and xv state up to the specified restoreIndex, and that it clears and rebuilds
rolling windows and the xv array from ProviderCache for Add/Remove operations
using the given index; ensure the <inheritdoc/> and method signature protected
override void RollbackState(int restoreIndex) remain unchanged and reference the
parameter name restoreIndex in the docs if param tags are present.
In `@src/s-z/Vortex/Vortex.StreamHub.cs`:
- Around line 123-136: The check "if (restoreIndex >= 0)" is redundant because
the method already returns when restoreIndex < 0; remove that conditional and
directly initialize the first quote: read ProviderCache[0] into an IQuote
(firstQuote) and assign _prevHigh, _prevLow, _prevClose from
firstQuote.High/Low/Close and set _isInitialized = true (keep the same symbols:
restoreIndex, ProviderCache, IQuote firstQuote, _prevHigh, _prevLow, _prevClose,
_isInitialized) so the initialization block runs unconditionally after the early
return.
- Around line 162-169: The if (restoreIndex >= 0) check is redundant because an
earlier early-return guarantees restoreIndex is non-negative; remove the
conditional and directly update prev values by retrieving IQuote lastQuote =
ProviderCache[restoreIndex] and assigning _prevHigh, _prevLow, and _prevClose
from lastQuote.High/Low/Close so the code always executes that update without
the unnecessary guard.
In `@src/s-z/Vwap/Vwap.StreamHub.cs`:
- Around line 75-79: Update the XML summary for the RollbackState method to
describe that it restores the cumulative state up to the provided cache index
rather than a timestamp; reference the method name RollbackState and the
parameter restoreIndex in the summary and param documentation so the docs match
the new rollback-by-index behavior.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (52)
.agents/skills/indicator-stream/SKILL.md.agents/skills/indicator-stream/references/rollback-patterns.mdsrc/_common/Quotes/Quote.StreamHub.cssrc/_common/StreamHub/StreamHub.cssrc/a-d/Adl/Adl.StreamHub.cssrc/a-d/Adx/Adx.StreamHub.cssrc/a-d/AtrStop/AtrStop.StreamHub.cssrc/a-d/Cci/Cci.StreamHub.cssrc/a-d/Chandelier/Chandelier.StreamHub.cssrc/a-d/Chop/Chop.StreamHub.cssrc/a-d/Cmo/Cmo.StreamHub.cssrc/a-d/ConnorsRsi/ConnorsRsi.StreamHub.cssrc/a-d/Dema/Dema.StreamHub.cssrc/a-d/Donchian/Donchian.StreamHub.cssrc/a-d/Dpo/Dpo.StreamHub.cssrc/e-k/Epma/Epma.StreamHub.cssrc/e-k/Fcb/Fcb.StreamHub.cssrc/e-k/FisherTransform/FisherTransform.StreamHub.cssrc/e-k/ForceIndex/ForceIndex.StreamHub.cssrc/e-k/HeikinAshi/HeikinAshi.StreamHub.cssrc/e-k/HtTrendline/HtTrendline.StreamHub.cssrc/e-k/Hurst/Hurst.StreamHub.cssrc/e-k/Ichimoku/Ichimoku.StreamHub.cssrc/e-k/Kvo/Kvo.StreamHub.cssrc/m-r/MaEnvelopes/MaEnvelopes.StreamHub.cssrc/m-r/Mama/Mama.StreamHub.cssrc/m-r/Mfi/Mfi.StreamHub.cssrc/m-r/ParabolicSar/ParabolicSar.StreamHub.cssrc/m-r/PivotPoints/PivotPoints.StreamHub.cssrc/m-r/Pivots/Pivots.StreamHub.cssrc/m-r/Pmo/Pmo.StreamHub.cssrc/m-r/Pvo/Pvo.StreamHub.cssrc/m-r/Renko/Renko.StreamHub.cssrc/m-r/RocWb/RocWb.StreamHub.cssrc/m-r/RollingPivots/RollingPivots.StreamHub.cssrc/m-r/Rsi/Rsi.StreamHub.cssrc/s-z/Slope/Slope.StreamHub.cssrc/s-z/Smi/Smi.StreamHub.cssrc/s-z/StarcBands/StarcBands.StreamHub.cssrc/s-z/Stc/Stc.StreamHub.cssrc/s-z/Stoch/Stoch.StreamHub.cssrc/s-z/StochRsi/StochRsi.StreamHub.cssrc/s-z/SuperTrend/SuperTrend.StreamHub.cssrc/s-z/T3/T3.StreamHub.cssrc/s-z/Tema/Tema.StreamHub.cssrc/s-z/Trix/Trix.StreamHub.cssrc/s-z/Tsi/Tsi.StreamHub.cssrc/s-z/UlcerIndex/UlcerIndex.StreamHub.cssrc/s-z/VolatilityStop/VolatilityStop.StreamHub.cssrc/s-z/Vortex/Vortex.StreamHub.cssrc/s-z/Vwap/Vwap.StreamHub.cssrc/s-z/WilliamsR/WilliamsR.StreamHub.cs
Signed-off-by: Dave Skender <[email protected]>
Responses to outside-diff review feedback1. VolatilityStop XML doc (Minor) —
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (10)
src/s-z/WilliamsR/WilliamsR.StreamHub.cs (1)
95-100:⚠️ Potential issue | 🟡 MinorUpdate XML summary to match index-based rollback contract.
Line 96 still says “specified timestamp”, but this override now restores by
restoreIndex. Please align wording to avoid IntelliSense confusion.✏️ Proposed doc fix
/// <summary> -/// Restores the rolling window state up to the specified timestamp. +/// Restores the rolling window state up to the specified index. /// Clears and rebuilds rolling windows from ProviderCache for Add/Remove operations. /// </summary>As per coding guidelines: "Update XML documentation for changed public APIs."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/s-z/WilliamsR/WilliamsR.StreamHub.cs` around lines 95 - 100, The XML summary for the RollbackState override still references a "specified timestamp" but the method signature is RollbackState(int restoreIndex); update the XML documentation on WilliamsR.StreamHub.RollbackState(int restoreIndex) to describe an index-based rollback (e.g., "Restores the rolling window state up to the specified restore index") and ensure any <param> or remarks mention restoreIndex rather than timestamp so IntelliSense reflects the index-based contract.src/m-r/RollingPivots/RollingPivots.StreamHub.cs (1)
117-120:⚠️ Potential issue | 🟡 MinorUpdate rollback XML docs to index-based terminology.
The summary still says “timestamp”, but the override now restores by index (
restoreIndex), which is misleading.✏️ Suggested doc fix
/// <summary> -/// Restores the rolling window and offset buffer state up to the specified timestamp. +/// Restores the rolling window and offset buffer state up to the specified index. /// Clears and rebuilds state from ProviderCache for Add/Remove operations. /// </summary>As per coding guidelines, "Update XML documentation for changed public APIs".
Also applies to: 122-122
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/m-r/RollingPivots/RollingPivots.StreamHub.cs` around lines 117 - 120, Update the XML documentation for the override that restores state to use index-based terminology instead of "timestamp": change the <summary> to say it "Restores the rolling window and offset buffer state up to the specified restore index" and update any parameter/docs that reference "timestamp" to reference the parameter name restoreIndex (also update the other occurrence around line 122) so the docs match the method signature and behavior in RollingPivots.StreamHub.cs.src/s-z/Stoch/Stoch.StreamHub.cs (1)
298-302:⚠️ Potential issue | 🟡 MinorStale rollback summary wording (
timestampvsrestoreIndex).Please align the XML summary with the new
int restoreIndexsignature.✏️ Proposed doc fix
- /// Restores the rolling window state up to the specified timestamp. + /// Restores the rolling window state up to the specified restore index.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/s-z/Stoch/Stoch.StreamHub.cs` around lines 298 - 302, The XML doc summary for the overridden method protected override void RollbackState(int restoreIndex) is stale (references "timestamp"); update the <summary> (and any <param> tag) to reference restoreIndex and its meaning (e.g., "Restores the rolling window state up to the specified restore index" and explain that restoreIndex is the index in the rolling window to which state will be restored) so the documentation matches the new int restoreIndex signature and behavior.src/e-k/Ichimoku/Ichimoku.StreamHub.cs (1)
220-224:⚠️ Potential issue | 🟡 MinorUpdate XML summary to match index-based rollback semantics.
The summary still says “specified timestamp” while the method now accepts
restoreIndex.✏️ Proposed doc fix
- /// Restores the rolling window states up to the specified timestamp. + /// Restores the rolling window states up to the specified restore index.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/e-k/Ichimoku/Ichimoku.StreamHub.cs` around lines 220 - 224, Update the XML summary for the overridden RollbackState method to reflect that it restores rolling window state up to a given index (restoreIndex) rather than a timestamp; locate the protected override void RollbackState(int restoreIndex) declaration and change the <summary> and any text referencing "timestamp" to describe index-based rollback semantics (e.g., "Restores the rolling window states up to the specified index (restoreIndex)"), keeping the <inheritdoc/> tag as appropriate.src/s-z/Smi/Smi.StreamHub.cs (1)
152-156:⚠️ Potential issue | 🟡 MinorRollback summary text should be updated to index semantics.
The XML comment still refers to “timestamp” while this override now takes
restoreIndex.✏️ Proposed doc fix
- /// Restores the SMI calculation state up to the specified timestamp. + /// Restores the SMI calculation state up to the specified restore index.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/s-z/Smi/Smi.StreamHub.cs` around lines 152 - 156, Update the XML documentation for the override RollbackState(int restoreIndex) to refer to "restore index" (or index-based semantics) instead of "timestamp" — change the <summary> text to something like "Restores the SMI calculation state up to the specified restore index" and ensure any parameter/inheritdoc remarks reflect the rename from timestamp to restoreIndex so the doc matches the method signature.src/a-d/Cci/Cci.StreamHub.cs (1)
44-49:⚠️ Potential issue | 🟡 MinorRollback XML summary still references timestamp semantics.
The summary should reflect
restoreIndex-based behavior now.✏️ Proposed doc fix
- /// Restores the CciList state up to the specified timestamp. + /// Restores the CciList state up to the specified restore index.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/a-d/Cci/Cci.StreamHub.cs` around lines 44 - 49, Update the XML summary on the protected override RollbackState(int restoreIndex) method to remove "timestamp" wording and describe restoreIndex-based behavior: state is restored up to the specified restoreIndex, clearing and rebuilding _cciList from ProviderCache to replay Add/Remove operations; ensure the param name restoreIndex is reflected in the summary or add a <param> tag mentioning restoreIndex if appropriate and remove any references to timestamps.src/s-z/Slope/Slope.StreamHub.cs (1)
142-153:⚠️ Potential issue | 🔴 CriticalPre-warmup rollback drops required buffer history.
At Line 142, returning when
restoreIndex < LookbackPeriods - 1skips rebuilding preserved prefix values. BecauseToIndicatorupdatesbufferbefore warmup gating, replay after an early historical mutation can reach calculable indices with an underfilled buffer and produce wrong regression statistics.Based on learnings: “When streaming hubs receive late inserts or revisions (Insert/RemoveAt/Add with same timestamp), they should rebuild from that point in time using the provider cache as the source and realign to match what the series implementation would produce on the full history.”💡 Proposed fix
- if (restoreIndex < LookbackPeriods - 1) + if (restoreIndex < 0) { return; } // Rebuild buffer from cache up to restoreIndex int startIdx = Math.Max(0, restoreIndex - LookbackPeriods + 1); for (int p = startIdx; p <= restoreIndex; p++) { buffer.Enqueue(ProviderCache[p].Value); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/s-z/Slope/Slope.StreamHub.cs` around lines 142 - 153, The early return when restoreIndex < LookbackPeriods - 1 drops preserved prefix values and causes underfilled buffer; remove that return and always rebuild the buffer from the provider cache starting at startIdx = Math.Max(0, restoreIndex - LookbackPeriods + 1) by enqueuing ProviderCache[p].Value for p in that range (the existing loop), ensuring buffer contains the same prefix the series implementation would have; after rebuilding the buffer, realign/replay from restoreIndex so ToIndicator sees the same history (i.e., perform the replay/update step that follows this rebuild) so warmup gating behaves correctly.src/s-z/Vortex/Vortex.StreamHub.cs (1)
110-114:⚠️ Potential issue | 🟡 MinorRollback XML doc still references timestamp.
Please update the summary to match
RollbackState(int restoreIndex).✏️ Suggested doc fix
- /// Restores the buffer state up to the specified timestamp. + /// Restores the buffer state up to the specified index.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/s-z/Vortex/Vortex.StreamHub.cs` around lines 110 - 114, The XML summary for the method protected override void RollbackState(int restoreIndex) incorrectly mentions a timestamp; update the <summary> to describe restoring the buffer state up to or using the provided restore index (e.g., "Restores the buffer state up to the specified restore index.") so the doc matches the RollbackState(int restoreIndex) signature and semantics; update any <inheritdoc/> usage if needed to ensure the summary reflects the restoreIndex parameter for RollbackState.src/a-d/Cmo/Cmo.StreamHub.cs (1)
66-71:⚠️ Potential issue | 🟡 MinorUpdate XML summary wording to index-based terminology.
The summary still says “specified timestamp” while the method now accepts
restoreIndex.✏️ Suggested doc fix
- /// Restores the tick buffer state up to the specified timestamp. + /// Restores the tick buffer state up to the specified index.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/a-d/Cmo/Cmo.StreamHub.cs` around lines 66 - 71, Update the XML documentation for the RollbackState method to use index-based terminology (mentioning restoreIndex) instead of "specified timestamp"; update the summary to say it restores the tick buffer state up to the specified restore index and that it clears and rebuilds _tickBuffer from ProviderCache for Add/Remove operations, and if present adjust any <param> or <inheritdoc/> comments to reference the restoreIndex parameter and index-based semantics.src/s-z/Stc/Stc.StreamHub.cs (1)
159-181:⚠️ Potential issue | 🟡 MinorRaw
%Krollback prefill can diverge fromToIndicatorwith NaN gaps.This prefill path can produce a numeric
rawAtPeven when fewer thanCyclePeriodsvalid MACD values exist, whileToIndicatorwould keep itNaN. That can skew restored_rawKBufferstate.As per coding guidelines: "Allow natural propagation of NaN values through calculations; never reject NaN inputs."🛠️ Suggested parity fix
int rStart = Math.Max(0, p + 1 - CyclePeriods); double hh = double.NegativeInfinity; double ll = double.PositiveInfinity; + int validCount = 0; for (int r = rStart; r <= p; r++) { MacdResult macdAtR = ProviderCache[r]; double macdValue = macdAtR.Macd ?? double.NaN; + if (double.IsNaN(macdValue)) + { + continue; + } + + validCount++; if (macdValue > hh) { hh = macdValue; } if (macdValue < ll) { ll = macdValue; } } MacdResult macdAtP = ProviderCache[p]; double macdAtPValue = macdAtP.Macd ?? double.NaN; - double rawAtP = (hh - ll) != 0 ? 100 * (macdAtPValue - ll) / (hh - ll) : 0; + double rawAtP = (!double.IsNaN(macdAtPValue) && validCount >= CyclePeriods) + ? ((hh - ll) != 0 ? 100d * (macdAtPValue - ll) / (hh - ll) : 0d) + : double.NaN; _rawKBuffer.Enqueue(rawAtP);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/s-z/Stc/Stc.StreamHub.cs` around lines 159 - 181, The rollback prefill computes rawAtP even when the sliding window contains NaN MACD entries, causing divergence from ToIndicator; modify the logic in the block using CyclePeriods, ProviderCache and MacdResult so that you count finite (non-NaN) MACD values across rStart..p and if that count is less than CyclePeriods set rawAtP = double.NaN (instead of computing 100*(macdAtPValue-ll)/(hh-ll)), then enqueue that NaN into _rawKBuffer so the restored state matches ToIndicator behavior.
🧹 Nitpick comments (1)
src/_common/StreamHub/StreamHub.cs (1)
177-179: Prefer using centralizedIndexBeforehelper for restore-index derivation.This keeps rollback-index semantics in one utility path and avoids repeating sentinel conversion logic.
♻️ Proposed refactor
- int gteIndex = ProviderCache.IndexGte(fromTimestamp); - int restoreIndex = (gteIndex == -1 ? ProviderCache.Count : gteIndex) - 1; + int restoreIndex = ProviderCache.IndexBefore(fromTimestamp);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/_common/StreamHub/StreamHub.cs` around lines 177 - 179, Replace the manual sentinel conversion for computing the restore index with the centralized helper: instead of calling ProviderCache.IndexGte(fromTimestamp) and subtracting 1 (with the -1 sentinel adjustment), call the existing IndexBefore helper to derive the restore index in one step; update the restore-index computation in StreamHub.cs to use ProviderCache.IndexBefore(fromTimestamp) (or the shared IndexBefore utility) so rollback-index semantics and sentinel handling are centralized via the IndexBefore symbol rather than duplicating the logic around ProviderCache.IndexGte and manual -1 adjustment.
🤖 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/a-d/Chandelier/Chandelier.StreamHub.cs`:
- Around line 138-145: IndexGte(ts) can return the first entry for a duplicate
timestamp causing misalignment with ProviderCache[restoreIndex]; fix by
computing the occurrence offset of that timestamp in ProviderCache up to
restoreIndex (count how many entries equal ts before restoreIndex), then set
quoteIndex = _quoteProvider.Results.IndexGte(ts) + occurrenceOffset and validate
bounds; if the computed quoteIndex is out of range or IndexGte returned < 0,
call the existing rebuild routine to rebuild/realign from that ProviderCache
restoreIndex (or the earliest affected index) so the series state matches what
the full-history series implementation would produce.
---
Outside diff comments:
In `@src/a-d/Cci/Cci.StreamHub.cs`:
- Around line 44-49: Update the XML summary on the protected override
RollbackState(int restoreIndex) method to remove "timestamp" wording and
describe restoreIndex-based behavior: state is restored up to the specified
restoreIndex, clearing and rebuilding _cciList from ProviderCache to replay
Add/Remove operations; ensure the param name restoreIndex is reflected in the
summary or add a <param> tag mentioning restoreIndex if appropriate and remove
any references to timestamps.
In `@src/a-d/Cmo/Cmo.StreamHub.cs`:
- Around line 66-71: Update the XML documentation for the RollbackState method
to use index-based terminology (mentioning restoreIndex) instead of "specified
timestamp"; update the summary to say it restores the tick buffer state up to
the specified restore index and that it clears and rebuilds _tickBuffer from
ProviderCache for Add/Remove operations, and if present adjust any <param> or
<inheritdoc/> comments to reference the restoreIndex parameter and index-based
semantics.
In `@src/e-k/Ichimoku/Ichimoku.StreamHub.cs`:
- Around line 220-224: Update the XML summary for the overridden RollbackState
method to reflect that it restores rolling window state up to a given index
(restoreIndex) rather than a timestamp; locate the protected override void
RollbackState(int restoreIndex) declaration and change the <summary> and any
text referencing "timestamp" to describe index-based rollback semantics (e.g.,
"Restores the rolling window states up to the specified index (restoreIndex)"),
keeping the <inheritdoc/> tag as appropriate.
In `@src/m-r/RollingPivots/RollingPivots.StreamHub.cs`:
- Around line 117-120: Update the XML documentation for the override that
restores state to use index-based terminology instead of "timestamp": change the
<summary> to say it "Restores the rolling window and offset buffer state up to
the specified restore index" and update any parameter/docs that reference
"timestamp" to reference the parameter name restoreIndex (also update the other
occurrence around line 122) so the docs match the method signature and behavior
in RollingPivots.StreamHub.cs.
In `@src/s-z/Slope/Slope.StreamHub.cs`:
- Around line 142-153: The early return when restoreIndex < LookbackPeriods - 1
drops preserved prefix values and causes underfilled buffer; remove that return
and always rebuild the buffer from the provider cache starting at startIdx =
Math.Max(0, restoreIndex - LookbackPeriods + 1) by enqueuing
ProviderCache[p].Value for p in that range (the existing loop), ensuring buffer
contains the same prefix the series implementation would have; after rebuilding
the buffer, realign/replay from restoreIndex so ToIndicator sees the same
history (i.e., perform the replay/update step that follows this rebuild) so
warmup gating behaves correctly.
In `@src/s-z/Smi/Smi.StreamHub.cs`:
- Around line 152-156: Update the XML documentation for the override
RollbackState(int restoreIndex) to refer to "restore index" (or index-based
semantics) instead of "timestamp" — change the <summary> text to something like
"Restores the SMI calculation state up to the specified restore index" and
ensure any parameter/inheritdoc remarks reflect the rename from timestamp to
restoreIndex so the doc matches the method signature.
In `@src/s-z/Stc/Stc.StreamHub.cs`:
- Around line 159-181: The rollback prefill computes rawAtP even when the
sliding window contains NaN MACD entries, causing divergence from ToIndicator;
modify the logic in the block using CyclePeriods, ProviderCache and MacdResult
so that you count finite (non-NaN) MACD values across rStart..p and if that
count is less than CyclePeriods set rawAtP = double.NaN (instead of computing
100*(macdAtPValue-ll)/(hh-ll)), then enqueue that NaN into _rawKBuffer so the
restored state matches ToIndicator behavior.
In `@src/s-z/Stoch/Stoch.StreamHub.cs`:
- Around line 298-302: The XML doc summary for the overridden method protected
override void RollbackState(int restoreIndex) is stale (references "timestamp");
update the <summary> (and any <param> tag) to reference restoreIndex and its
meaning (e.g., "Restores the rolling window state up to the specified restore
index" and explain that restoreIndex is the index in the rolling window to which
state will be restored) so the documentation matches the new int restoreIndex
signature and behavior.
In `@src/s-z/Vortex/Vortex.StreamHub.cs`:
- Around line 110-114: The XML summary for the method protected override void
RollbackState(int restoreIndex) incorrectly mentions a timestamp; update the
<summary> to describe restoring the buffer state up to or using the provided
restore index (e.g., "Restores the buffer state up to the specified restore
index.") so the doc matches the RollbackState(int restoreIndex) signature and
semantics; update any <inheritdoc/> usage if needed to ensure the summary
reflects the restoreIndex parameter for RollbackState.
In `@src/s-z/WilliamsR/WilliamsR.StreamHub.cs`:
- Around line 95-100: The XML summary for the RollbackState override still
references a "specified timestamp" but the method signature is RollbackState(int
restoreIndex); update the XML documentation on
WilliamsR.StreamHub.RollbackState(int restoreIndex) to describe an index-based
rollback (e.g., "Restores the rolling window state up to the specified restore
index") and ensure any <param> or remarks mention restoreIndex rather than
timestamp so IntelliSense reflects the index-based contract.
---
Nitpick comments:
In `@src/_common/StreamHub/StreamHub.cs`:
- Around line 177-179: Replace the manual sentinel conversion for computing the
restore index with the centralized helper: instead of calling
ProviderCache.IndexGte(fromTimestamp) and subtracting 1 (with the -1 sentinel
adjustment), call the existing IndexBefore helper to derive the restore index in
one step; update the restore-index computation in StreamHub.cs to use
ProviderCache.IndexBefore(fromTimestamp) (or the shared IndexBefore utility) so
rollback-index semantics and sentinel handling are centralized via the
IndexBefore symbol rather than duplicating the logic around
ProviderCache.IndexGte and manual -1 adjustment.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (52)
.agents/skills/indicator-stream/SKILL.md.agents/skills/indicator-stream/references/rollback-patterns.mdsrc/_common/Quotes/Quote.StreamHub.cssrc/_common/StreamHub/StreamHub.cssrc/a-d/Adl/Adl.StreamHub.cssrc/a-d/Adx/Adx.StreamHub.cssrc/a-d/AtrStop/AtrStop.StreamHub.cssrc/a-d/Cci/Cci.StreamHub.cssrc/a-d/Chandelier/Chandelier.StreamHub.cssrc/a-d/Chop/Chop.StreamHub.cssrc/a-d/Cmo/Cmo.StreamHub.cssrc/a-d/ConnorsRsi/ConnorsRsi.StreamHub.cssrc/a-d/Dema/Dema.StreamHub.cssrc/a-d/Donchian/Donchian.StreamHub.cssrc/a-d/Dpo/Dpo.StreamHub.cssrc/e-k/Epma/Epma.StreamHub.cssrc/e-k/Fcb/Fcb.StreamHub.cssrc/e-k/FisherTransform/FisherTransform.StreamHub.cssrc/e-k/ForceIndex/ForceIndex.StreamHub.cssrc/e-k/HeikinAshi/HeikinAshi.StreamHub.cssrc/e-k/HtTrendline/HtTrendline.StreamHub.cssrc/e-k/Hurst/Hurst.StreamHub.cssrc/e-k/Ichimoku/Ichimoku.StreamHub.cssrc/e-k/Kvo/Kvo.StreamHub.cssrc/m-r/MaEnvelopes/MaEnvelopes.StreamHub.cssrc/m-r/Mama/Mama.StreamHub.cssrc/m-r/Mfi/Mfi.StreamHub.cssrc/m-r/ParabolicSar/ParabolicSar.StreamHub.cssrc/m-r/PivotPoints/PivotPoints.StreamHub.cssrc/m-r/Pivots/Pivots.StreamHub.cssrc/m-r/Pmo/Pmo.StreamHub.cssrc/m-r/Pvo/Pvo.StreamHub.cssrc/m-r/Renko/Renko.StreamHub.cssrc/m-r/RocWb/RocWb.StreamHub.cssrc/m-r/RollingPivots/RollingPivots.StreamHub.cssrc/m-r/Rsi/Rsi.StreamHub.cssrc/s-z/Slope/Slope.StreamHub.cssrc/s-z/Smi/Smi.StreamHub.cssrc/s-z/StarcBands/StarcBands.StreamHub.cssrc/s-z/Stc/Stc.StreamHub.cssrc/s-z/Stoch/Stoch.StreamHub.cssrc/s-z/StochRsi/StochRsi.StreamHub.cssrc/s-z/SuperTrend/SuperTrend.StreamHub.cssrc/s-z/T3/T3.StreamHub.cssrc/s-z/Tema/Tema.StreamHub.cssrc/s-z/Trix/Trix.StreamHub.cssrc/s-z/Tsi/Tsi.StreamHub.cssrc/s-z/UlcerIndex/UlcerIndex.StreamHub.cssrc/s-z/VolatilityStop/VolatilityStop.StreamHub.cssrc/s-z/Vortex/Vortex.StreamHub.cssrc/s-z/Vwap/Vwap.StreamHub.cssrc/s-z/WilliamsR/WilliamsR.StreamHub.cs
Co-authored-by: DaveSkender <[email protected]>
Co-authored-by: DaveSkender <[email protected]>
Replaces the per-indicator
ProviderCache.IndexGte(timestamp)pattern in everyRollbackStateoverride with a single base-class computation, eliminating a class of-1sentinel bugs and reducing boilerplate across all 49 StreamHub implementations.Architectural change
RollbackState(DateTime timestamp)→RollbackState(int restoreIndex)The base class now computes
restoreIndexviaIndexBefore(fromTimestamp)before calling the virtual method:-1= no entries precede the rollback point (reset to initial state)>= 0= lastProviderCacheindex to preserveThis eliminates the repeated
IndexGte→ check for-1→ subtract 1 pattern that 34 implementations got wrong when the timestamp was beyond all cache entries.Changes
Base class (
StreamHub.cs)RollbackState(DateTime timestamp)→RollbackState(int restoreIndex)RemoveRangecomputesrestoreIndexcentrally before calling overrideRebuildcomputesrestoreIndexfromCache.IndexGtebefore calling overrideIndexBefore<T>utility inStreamHub.Utilities.csAll 49 StreamHub implementations
IndexGte+ sentinel handling — replaced with directrestoreIndexusageif (restoreIndex < 0) return;replaces multi-branch checksBug fix — ConnorsRsi (
ConnorsRsi.StreamHub.cs)RollbackStatereplay ati == 0did not enqueue the gain seed intogainBuffer, leaving PercentRank one element short after early rollbacksgainBuffer.Enqueue(...)ati == 0to matchToIndicatorbehavior — confirmed by test failure before fixDoc fix — VolatilityStop (
VolatilityStop.StreamHub.cs)ADL optimization (original P011 scope)
_previousAdlfield to avoidCache[i - 1]dereference on every tickRollbackStaterestores from last cache entrySkill documentation
indicator-stream/SKILL.mdandrollback-patterns.mdto reflect index-based patternPlan reference
streaming-indicators.plan.md)