Skip to content

Build 954: Bot Audit Remediation & Protocol Hardening#24

Closed
mkalhitti-cloud wants to merge 2 commits into
mainfrom
build/954-bot-audit-fixes
Closed

Build 954: Bot Audit Remediation & Protocol Hardening#24
mkalhitti-cloud wants to merge 2 commits into
mainfrom
build/954-bot-audit-fixes

Conversation

@mkalhitti-cloud
Copy link
Copy Markdown
Owner

Surgical fixes for IPC ghost connection, RETEST null order leak, and activeMode normalization. Injected Section 12 into Standards Manifesto for Maximum Autonomy and Protected Legacy Archive.

mkalhitti-cloud and others added 2 commits March 4, 2026 20:44
- Add TargetSnapshot class for bracket state capture
- Extend PendingStopReplacement with CapturedTargets
- Fix follower stop-cancel black hole in HandleMatchedFollowerOrder
- Add RestoreCascadedTargets via TriggerCustomEvent
- Fix CreateNewStopOrder to re-link OcoGroupId
- Add bracket restore to V8.30 timeout fallback path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e fallback

Fix 1 (V12_001.cs): Stub ConnectToStrategy() with early return -- strategy no
longer hosts IPC server after Phase 6 pruning. Panel runs in standalone UI mode;
SendCommand calls safely no-op via tcpStream null guard.

Fix 2 (V12_002.Entries.Retest.cs): Insert return; inside null-order guard after
SubmitOrderUnmanaged fails. Prevents retestFiredThisSession latch and SIMA
dispatch from arming on a failed order submission.

Fix 3 (V12_001.cs): Add else branch in LoadConfig() to normalize both activeMode
and selectedConfigMode to RMA when a deprecated/pruned mode is found in saved
config. Prevents GetSettings() from loading garbage data from a deleted slot.

Build tag incremented to 954.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@deepsource-io
Copy link
Copy Markdown

deepsource-io Bot commented Mar 6, 2026

DeepSource Code Review

We reviewed changes in 24ec680...7fc6b4b on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

Important

Some issues found as part of this review are outside of the diff in this pull request and aren't shown in the inline review comments due to GitHub's API limitations. You can see those issues on the DeepSource dashboard.

PR Report Card

Overall Grade  

Focus Area: Hygiene
Security  

Reliability  

Complexity  

Hygiene  

Feedback

  • Mixed responsibilities inside single files
    • Multiple namespaces and sprawling methods indicate files bundle unrelated concerns, which produces large, hard-to-reason blobs; splitting types and namespaces into focused files restores cohesion and keeps methods small and targeted.
  • Scattershot null-guarding instead of a single contract
    • Repeated, simplifiable nullable checks appear because validation is sprinkled throughout logic rather than enforced at a boundary; adopt nullable-reference types or centralized guard helpers and validate at entry points to remove redundant checks.
  • Accreted branching left without cleanup
    • Extremely high branch counts and unreachable statements come from piling new cases onto existing methods instead of extracting behavior, leaving dead code behind; break the pattern by extracting well-named helpers, preferring early returns, and pruning unreachable paths.

Code Review Summary

Analyzer Status Updated (UTC) Details
C# Mar 6, 2026 9:17p.m. Review ↗
Secrets Mar 6, 2026 9:17p.m. Review ↗


foreach (TargetSnapshot snap in capturedTargets)
{
if (snap == null || snap.CapturedOrder == null) continue;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Null check can be simplified


The ?. operator allows you to access a property or a member only if it is non-null. Consider simplifying the highlighted expression, i.e. the object and its member's null checks via the usage of this ?. operator.

Comment thread src/V12_002.Trailing.cs
{
var _tD2 = GetTargetOrdersDictionary(_t2);
Order _tO2;
if (_tD2 != null && _tD2.TryGetValue(entryName, out _tO2) && _tO2 != null
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nullable check expression can be simplified


While it is common to explicitly check an object's nullability before accessing its value, you can further simplify this expression by
either using the conditional access operator ? or pattern matching instead. These proposed solutions are succinct and reduce your
keystrokes.

Comment thread src/V12_002.Trailing.cs
{
var _tD = GetTargetOrdersDictionary(_t);
Order _tO;
if (_tD != null && _tD.TryGetValue(entryName, out _tO) && _tO != null
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nullable check expression can be simplified


While it is common to explicitly check an object's nullability before accessing its value, you can further simplify this expression by
either using the conditional access operator ? or pattern matching instead. These proposed solutions are succinct and reduce your
keystrokes.

Comment thread src/V12_002.Trailing.cs
{
var _tD = GetTargetOrdersDictionary(_t);
Order _tO;
if (_tD != null && _tD.TryGetValue(entryName, out _tO) && _tO != null
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nullable check expression can be simplified


While it is common to explicitly check an object's nullability before accessing its value, you can further simplify this expression by
either using the conditional access operator ? or pattern matching instead. These proposed solutions are succinct and reduce your
keystrokes.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 6, 2026

Greptile Summary

This PR delivers three surgical Build 954 fixes — IPC ghost-connection removal, RETEST null-order state leak, and deprecated activeMode fallback — on top of the larger Build 950 OCO cascade bracket-restoration FSM that was already partially landed. The bracket restoration work spans five files: a new TargetSnapshot class, extended PendingStopReplacement, snapshot capture in UpdateStopOrder, restoration dispatch in both the master and follower cancel callbacks, and a new RestoreCascadedTargets method.

Key changes and concerns:

  • V12_002.Trailing.cs — race condition in target snapshot timing: In both TryAdd paths, newPending is inserted into the shared pendingStopReplacements dictionary before CapturedTargets / BracketRestorationNeeded are assigned. A stop-cancel callback arriving in that window will see an incomplete record and skip bracket restoration entirely — the exact scenario this build targets.
  • V12_002.Orders.Callbacks.cs — follower stop path TOCTOU: RemainingContracts is read once without stateLock for the guard check, then re-read under the lock for the actual value passed to CreateNewStopOrder. A fill in that window could produce a 0-quantity stop order.
  • V12_001.cs — IPC intentionally disabled: ConnectToStrategy() early-returns, leaving the full connection body as dead code. The intent is documented, but isConnected and retry-state variables remain at their initial values permanently, which may mislead any status-display logic that reads them.
  • V12_002.Entries.Retest.cs: Clean, isolated fix — return after null order prevents unintended session latch and SIMA dispatch.
  • V12_002.Orders.Management.cs: RestoreCascadedTargets and OcoGroupId threading into CreateNewStopOrder are well-structured and run on the strategy thread, avoiding additional locking needs.

Confidence Score: 2/5

  • Not safe to merge as-is — the race condition in V12_002.Trailing.cs can silently prevent OCO bracket restoration in the exact scenario this build is designed to fix.
  • The core Build 954 fixes (RETEST null leak, deprecated mode fallback) are correct and isolated. However, the Build 950 bracket restoration — the most complex and consequential logic in this PR — has a race condition: CapturedTargets is populated after the PendingStopReplacement is inserted into the shared dictionary. A stop-cancel callback in that window sees BracketRestorationNeeded = false and silently skips restoration, leaving a naked position with no targets. The follower callback also has a minor TOCTOU on RemainingContracts. These are real trading-safety issues on a live multi-account strategy.
  • src/V12_002.Trailing.cs (race condition in both TryAdd paths) and src/V12_002.Orders.Callbacks.cs (TOCTOU in follower RemainingContracts read) need attention before merge.

Important Files Changed

Filename Overview
src/V12_002.Trailing.cs Adds OCO target snapshot capture before stop cancel. Contains a race condition where CapturedTargets is set on newPending after it has already been inserted into the shared pendingStopReplacements dictionary, allowing a concurrent callback to see an incomplete record and skip bracket restoration.
src/V12_002.Orders.Callbacks.cs Adds follower stop replacement handling and master-path bracket restoration via TriggerCustomEvent. Follower path has a TOCTOU read of RemainingContracts (once without lock, once with lock); the window is narrow but inconsistent with best practices.
src/V12_002.Orders.Management.cs Adds RestoreCascadedTargets method and threads OcoGroupId into replacement stop order submissions for both fleet-follower and local paths. Logic is sound; target dict updates run on strategy thread via TriggerCustomEvent so no additional locking is needed there.
src/V12_001.cs IPC ConnectToStrategy disabled via early return, leaving the entire connection body as dead code. Deprecated-mode fallback to "RMA" is correct. Dead code may mislead future readers about actual runtime state of isConnected/tcpStream.
src/V12_002.Entries.Retest.cs Adds return after null order error to prevent session latch and spurious SIMA dispatch. Clean, targeted fix with no side-effects.
src/V12_002.cs Updates BUILD_TAG to "954", adds TargetSnapshot nested class, and extends PendingStopReplacement with CapturedTargets / BracketRestorationNeeded. Structural changes are clean.
docs/brain/walkthrough.md Documentation update for Build 950 OCO Cascade Fix. Accurately describes the two-part FSM fix, affected files, and verification steps.

Sequence Diagram

sequenceDiagram
    participant TS as UpdateStopOrder<br/>(Trailing.cs)
    participant Dict as pendingStopReplacements<br/>(ConcurrentDictionary)
    participant OUC as OnOrderUpdate/<br/>OnAccountOrderUpdate
    participant HOC as HandleOrderCancelled /<br/>HandleMatchedFollowerOrder
    participant CSO as CreateNewStopOrder
    participant RCT as RestoreCascadedTargets

    TS->>TS: Snapshot Working targets into _b950Targets
    Note over TS: ⚠️ BUG: snapshot happens AFTER TryAdd
    TS->>Dict: TryAdd(entryName, newPending)<br/>[CapturedTargets=null at this point]
    TS->>Dict: newPending.CapturedTargets = snapshot<br/>[race window between these two lines]

    OUC->>HOC: stop cancel event arrives
    HOC->>Dict: lookup pendingStopReplacements
    alt CapturedTargets already set (no race)
        HOC->>CSO: CreateNewStopOrder(entryName, qty, price)
        HOC->>RCT: TriggerCustomEvent → RestoreCascadedTargets
        RCT->>RCT: Check each snap.CapturedOrder.OrderState
        RCT->>RCT: Re-submit Cancelled targets via SubmitOrderUnmanaged / Account.Submit
        RCT->>RCT: tDict[entryName] = newTarget
    else Race: CapturedTargets=null (BracketRestorationNeeded=false)
        HOC->>CSO: CreateNewStopOrder(entryName, qty, price)
        Note over HOC: RestoreCascadedTargets skipped — bracket not restored
    end
Loading

Comments Outside Diff (1)

  1. src/V12_002.Trailing.cs, line 528-574 (link)

    Race condition: CapturedTargets populated after TryAdd

    When TryAdd succeeds at line 528, newPending is placed into the shared pendingStopReplacements dictionary with CapturedTargets = null and BracketRestorationNeeded = false. The unconditional snapshot block (lines 562-574) only populates CapturedTargets after the entry is already visible to other threads.

    If the broker's stop-cancel callback fires (on OnOrderUpdate / OnAccountOrderUpdate) between the moment TryAdd returns and the moment newPending.CapturedTargets is assigned, both HandleOrderCancelled and HandleMatchedFollowerOrder will see BracketRestorationNeeded == false and skip RestoreCascadedTargets entirely — defeating the entire OCO cascade restore feature in a tight-window race.

    The same issue exists in the second TryAdd block around line 595-618.

    The snapshot should be captured before TryAdd, so the object entering the dictionary is already fully initialised:

    // Build 950: Snapshot before TryAdd so any callback sees a complete record.
    var _b950Targets = new System.Collections.Generic.List<TargetSnapshot>();
    for (int _t = 1; _t <= 5; _t++)
    {
        var _tD = GetTargetOrdersDictionary(_t);
        Order _tO;
        if (_tD != null && _tD.TryGetValue(entryName, out _tO) && _tO != null
            && (_tO.OrderState == OrderState.Working || _tO.OrderState == OrderState.Accepted))
            _b950Targets.Add(new TargetSnapshot { TargetNum = _t, Price = _tO.LimitPrice, Qty = _tO.Quantity, CapturedOrder = _tO });
    }
    var newPending = new PendingStopReplacement
    {
        EntryName   = entryName,
        Quantity    = pos.RemainingContracts,
        StopPrice   = validatedStopPrice,
        Direction   = pos.Direction,
        OldOrder    = currentStop,
        CreatedTime = DateTime.Now,
        CapturedTargets          = _b950Targets.Count > 0 ? _b950Targets.ToArray() : null,
        BracketRestorationNeeded = _b950Targets.Count > 0
    };
    if (pendingStopReplacements.TryAdd(entryName, newPending)) { ... }

    The same correction should be applied to the second TryAdd block (around line 584-618).

Last reviewed commit: 7fc6b4b

Comment thread src/V12_001.cs
{
// [Build 954]: IPC deprecated -- strategy no longer hosts IPC server (Phase 6 pruning).
// Panel operates in standalone UI mode. All SendCommand calls are safely no-oped via tcpStream null guard.
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Dead code left in place after early return

The return; at line 3003 leaves the entire try/catch block unreachable. While the comment is clear about the intent, the dead code includes non-trivial logic: thread creation (receiveThread), TcpClient/TcpStream allocation, and a catch that resets isConnected / increments _ipcRetryCount. If isConnected or _ipcRetryCount are read elsewhere (e.g. a status display), they will permanently show their initial/stale values rather than reflecting "intentionally offline".

Consider either removing the body entirely (leaving only the comment + return) or adding a one-time log line that records the intentional no-op state so the status LED / connection state surface the right information.

Comment on lines +600 to +605
PositionInfo _rPos;
if (activePositions.TryGetValue(_psr.Key, out _rPos) && _rPos.RemainingContracts > 0)
{
int _rQty;
lock (stateLock) { _rQty = _rPos.RemainingContracts; }
CreateNewStopOrder(_psr.Key, _rQty, _psr.Value.StopPrice, _psr.Value.Direction);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

TOCTOU on RemainingContracts in follower path

The guard at line 601 reads _rPos.RemainingContracts > 0 without holding stateLock, then immediately re-reads the same field under the lock at line 604. Between these two reads another thread could decrement RemainingContracts to 0 (e.g. a fill callback), so _rQty could be 0 or negative despite the earlier check passing, and CreateNewStopOrder would be called with _rQty = 0.

The simpler — and consistent — fix is to read once under the lock:

int _rQty;
lock (stateLock) { _rQty = _rPos.RemainingContracts; }
if (_rQty > 0)
{
    CreateNewStopOrder(_psr.Key, _rQty, _psr.Value.StopPrice, _psr.Value.Direction);
    ...
}

Note: the master path in HandleOrderCancelled (line 372-374) has the same pattern without any lock at all — consistency across both paths would be worth aligning.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Build 954 focuses on hardening order-management edge cases (especially stop replacement/OCO bracket integrity) and remediating a RETEST null-order leak, plus normalizing deprecated UI config modes and deprecating IPC usage in the panel.

Changes:

  • Add bracket target snapshot/restore logic to recover from broker OCO cascade cancellations during stop replacement (Build 950 behavior carried into 954).
  • Prevent RETEST from latching session/dispatching SIMA when entry submission returns null.
  • Normalize deprecated/unrecognized activeMode values to RMA, and short-circuit panel IPC connection logic.

Reviewed changes

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

Show a summary per file
File Description
src/V12_002.cs Bumps build tag; introduces TargetSnapshot and extends PendingStopReplacement for bracket restoration metadata.
src/V12_002.Trailing.cs Captures target snapshots before stop cancel and triggers target restoration after emergency stop creation.
src/V12_002.Orders.Management.cs Re-links replacement stops to the original OCO group; adds RestoreCascadedTargets to re-submit cascade-cancelled targets.
src/V12_002.Orders.Callbacks.cs Restores targets after master stop replacement; adds follower stop-cancel handling via OnAccountOrderUpdate path.
src/V12_002.Entries.Retest.cs Early-return after NULL unmanaged submit to avoid subsequent state latching/dispatch.
src/V12_001.cs Adds deprecated-mode fallback; disables IPC connect path (currently via unconditional return).
docs/brain/walkthrough.md Documents the OCO cascade fix and verification steps (currently out of sync with Build 954 + IPC deprecation).

Comment on lines +637 to +643
string tSig = "T" + snap.TargetNum + "_" + entryName;
newTarget = direction == MarketPosition.Long
? SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.Limit,
snap.Qty, restoredPrice, 0, bracketOcoId, tSig)
: SubmitOrderUnmanaged(0, OrderAction.BuyToCover, OrderType.Limit,
snap.Qty, restoredPrice, 0, bracketOcoId, tSig);
}
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

In the unmanaged/local restore path, the target signal name ("T{n}_" + entryName) is not trimmed and can exceed the established max length for target signals. Use the same trimming approach as the follower path (e.g., SymmetryTrim to 40 chars / ensure <= 50) to avoid NinjaTrader signal truncation/collisions.

Copilot generated this review using guidance from repository custom instructions.
Comment thread src/V12_001.cs
Comment on lines 2999 to 3006
private void ConnectToStrategy()
{
// [Build 954]: IPC deprecated -- strategy no longer hosts IPC server (Phase 6 pruning).
// Panel operates in standalone UI mode. All SendCommand calls are safely no-oped via tcpStream null guard.
return;
try
{
lock (tcpLock)
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

ConnectToStrategy now has an unconditional return before a try block, leaving the subsequent statements unreachable. This will fail compilation (unreachable code). If IPC is deprecated, remove/comment the old implementation or gate it behind a conditional compilation symbol instead of returning mid-method.

Copilot uses AI. Check for mistakes.
Comment thread docs/brain/walkthrough.md
Comment on lines +79 to +86
- src/V12_002.cs -- TargetSnapshot class, PendingStopReplacement extended, BUILD_TAG = "950"
- src/V12_002.Trailing.cs -- target snapshot in UpdateStopOrder, restore in V8.30 timeout
- src/V12_002.Orders.Callbacks.cs -- follower stop handler + master bracket restore
- src/V12_002.Orders.Management.cs -- RestoreCascadedTargets(), CreateNewStopOrder OcoId fix

### Verification
1. Sim session: Enter 4-contract position, verify bracket (Stop + T1/T2/T3) all Working
2. Send BE_CUSTOM via IPC -- confirm logs show "[B950] Target T1 restored", "[B950] Target T2 restored"
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

walkthrough.md references BUILD_TAG = "950" and suggests verification via IPC commands, but this PR updates BUILD_TAG to 954 and also disables IPC connectivity in the panel. Please update the walkthrough to match the current build number and the current (non-IPC) verification procedure so operators aren’t following a stale runbook.

Suggested change
- src/V12_002.cs -- TargetSnapshot class, PendingStopReplacement extended, BUILD_TAG = "950"
- src/V12_002.Trailing.cs -- target snapshot in UpdateStopOrder, restore in V8.30 timeout
- src/V12_002.Orders.Callbacks.cs -- follower stop handler + master bracket restore
- src/V12_002.Orders.Management.cs -- RestoreCascadedTargets(), CreateNewStopOrder OcoId fix
### Verification
1. Sim session: Enter 4-contract position, verify bracket (Stop + T1/T2/T3) all Working
2. Send BE_CUSTOM via IPC -- confirm logs show "[B950] Target T1 restored", "[B950] Target T2 restored"
- src/V12_002.cs -- TargetSnapshot class, PendingStopReplacement extended, BUILD_TAG = "954"
- src/V12_002.Trailing.cs -- target snapshot in UpdateStopOrder, restore in V8.30 timeout
- src/V12_002.Orders.Callbacks.cs -- follower stop handler + master bracket restore
- src/V12_002.Orders.Management.cs -- RestoreCascadedTargets(), CreateNewStopOrder OcoId fix
### Verification
1. Sim session: Enter 4-contract position, verify bracket (Stop + T1/T2/T3) all Working
2. Trigger BE_CUSTOM from the strategy control panel (non-IPC path) -- confirm logs show "[B954] Target T1 restored", "[B954] Target T2 restored"

Copilot uses AI. Check for mistakes.
newStop = pos.ExecutingAccount.CreateOrder(Instrument, exitAction,
OrderType.StopMarket, TimeInForce.Gtc, quantity, 0, stopPrice, sigName, sigName, null);
OrderType.StopMarket, TimeInForce.Gtc, quantity, 0, stopPrice, _b950OcoId, sigName, null);
pos.ExecutingAccount.Submit(new[] { newStop });
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

In the follower branch, the result of ExecutingAccount.CreateOrder is submitted immediately, before checking for null. If CreateOrder returns null, Submit(new[] { newStop }) can throw and the later null-handling/flatten path is bypassed, leaving the position potentially unprotected. Null-guard the order before Submit (and consider wrapping Submit in try/catch consistent with the repo’s CreateOrder-null convention).

Suggested change
pos.ExecutingAccount.Submit(new[] { newStop });
// Guard against null CreateOrder results and submit failures to preserve later null-handling logic.
if (newStop != null)
{
try
{
pos.ExecutingAccount.Submit(new[] { newStop });
}
catch (Exception submitEx)
{
// On submit failure, fall back to the same path as a null order (newStop == null).
Print("Error submitting follower replacement stop for " + entryName + ": " + submitEx.Message);
newStop = null;
}
}

Copilot uses AI. Check for mistakes.
Comment thread src/V12_002.Trailing.cs
Comment on lines +561 to 574
// Build 950: Snapshot Working/Accepted targets before cancel for OCO cascade restoration.
{
var _b950Targets = new System.Collections.Generic.List<TargetSnapshot>();
for (int _t = 1; _t <= 5; _t++)
{
var _tD = GetTargetOrdersDictionary(_t);
Order _tO;
if (_tD != null && _tD.TryGetValue(entryName, out _tO) && _tO != null
&& (_tO.OrderState == OrderState.Working || _tO.OrderState == OrderState.Accepted))
_b950Targets.Add(new TargetSnapshot { TargetNum = _t, Price = _tO.LimitPrice, Qty = _tO.Quantity, CapturedOrder = _tO });
}
newPending.CapturedTargets = _b950Targets.Count > 0 ? _b950Targets.ToArray() : null;
newPending.BracketRestorationNeeded = _b950Targets.Count > 0;
}
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

When pendingStopReplacements.TryAdd fails, the snapshot block populates CapturedTargets on the local newPending object, which is not the instance stored in pendingStopReplacements. This can drop the captured target snapshot entirely on the TryAdd-failed path. Populate CapturedTargets/BracketRestorationNeeded on the actual pending instance in the dictionary (either the one returned by TryGetValue or via AddOrUpdate pattern).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

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

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: 7fc6b4ba92

ℹ️ 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 src/V12_001.cs
{
// [Build 954]: IPC deprecated -- strategy no longer hosts IPC server (Phase 6 pruning).
// Panel operates in standalone UI mode. All SendCommand calls are safely no-oped via tcpStream null guard.
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Remove unconditional return in ConnectToStrategy

ConnectToStrategy() now exits immediately, so SendCommand() can never establish tcpStream and every panel action silently becomes a no-op. This is a functional regression because the strategy still starts and uses the IPC server (StartIpcServer() in src/V12_002.cs and command handling in src/V12_002.UI.IPC.cs), so disabling connection at the indicator side breaks runtime control/sync flows rather than removing dead code.

Useful? React with 👍 / 👎.

mkalhitti-cloud added a commit that referenced this pull request Mar 6, 2026
FINDING 1 (CRITICAL) -- V12_002.Trailing.cs:
- Snapshot CapturedTargets/BracketRestorationNeeded BEFORE pendingStopReplacements.TryAdd
  in both TryAdd paths (CancelPending/Submitted and Working/Accepted state handlers).
- Eliminated race window where stop-cancel callback could read a partially-constructed
  PendingStopReplacement with BracketRestorationNeeded=false and skip RestoreCascadedTargets.
- Removed now-redundant post-TryAdd snapshot blocks (were dead/duplicate after fix).

FINDING 2 (HIGH) -- V12_002.Orders.Callbacks.cs:
- HandleOrderCancelled (master path): snapshot RemainingContracts under stateLock once;
  use same snapshot for guard check and CreateNewStopOrder call. Eliminates 0-qty stop risk.
- OnAccountOrderUpdate (follower path): move RemainingContracts guard inside stateLock so
  check and use are atomic. Eliminates TOCTOU on follower stop replacement qty.

FINDING 3 (LOW) -- V12_001.cs:
- Remove unreachable try/catch body after intentional return stub in ConnectToStrategy().
  SendCommand() safely no-ops via tcpStream null guard -- no behavior change.

Bump BUILD_TAG -> 955. ASCII gate: PASS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mkalhitti-cloud
Copy link
Copy Markdown
Owner Author

Superseded by PR #25 (Build 955).

This PR contained a critical race condition in V12_002.Trailing.cs identified by Greptile (Confidence 2/5 -- not safe to merge): CapturedTargets was populated AFTER TryAdd, leaving a window where a stop-cancel callback would see BracketRestorationNeeded = false and silently skip OCO bracket restoration.

PR #25 addresses all three audit findings:

  • CRITICAL: snapshot-before-TryAdd in both state-handler paths (Trailing.cs)
  • HIGH: atomic stateLock snapshot for RemainingContracts in master + follower TOCTOU paths (Orders.Callbacks.cs)
  • LOW: removed unreachable IPC dead code from ConnectToStrategy() (V12_001.cs)

Closing in favour of the clean branch.

@mkalhitti-cloud mkalhitti-cloud deleted the build/954-bot-audit-fixes branch April 21, 2026 23:57
mkalhitti-cloud added a commit that referenced this pull request May 20, 2026
FINDING 1 (CRITICAL) -- V12_002.Trailing.cs:
- Snapshot CapturedTargets/BracketRestorationNeeded BEFORE pendingStopReplacements.TryAdd
  in both TryAdd paths (CancelPending/Submitted and Working/Accepted state handlers).
- Eliminated race window where stop-cancel callback could read a partially-constructed
  PendingStopReplacement with BracketRestorationNeeded=false and skip RestoreCascadedTargets.
- Removed now-redundant post-TryAdd snapshot blocks (were dead/duplicate after fix).

FINDING 2 (HIGH) -- V12_002.Orders.Callbacks.cs:
- HandleOrderCancelled (master path): snapshot RemainingContracts under stateLock once;
  use same snapshot for guard check and CreateNewStopOrder call. Eliminates 0-qty stop risk.
- OnAccountOrderUpdate (follower path): move RemainingContracts guard inside stateLock so
  check and use are atomic. Eliminates TOCTOU on follower stop replacement qty.

FINDING 3 (LOW) -- V12_001.cs:
- Remove unreachable try/catch body after intentional return stub in ConnectToStrategy().
  SendCommand() safely no-ops via tcpStream null guard -- no behavior change.

Bump BUILD_TAG -> 955. ASCII gate: PASS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants