Skip to content

[FIX] Build 972: Follower order loss repair (Move-Grace & REAPER sync)#36

Merged
mkalhitti-cloud merged 8 commits into
mainfrom
feat/follower-loss-fix-b972
Mar 12, 2026
Merged

[FIX] Build 972: Follower order loss repair (Move-Grace & REAPER sync)#36
mkalhitti-cloud merged 8 commits into
mainfrom
feat/follower-loss-fix-b972

Conversation

@mkalhitti-cloud
Copy link
Copy Markdown
Owner

@mkalhitti-cloud mkalhitti-cloud commented Mar 11, 2026

Fixes the issue where follower orders are lost during master chart-moves (Build 948 incident).

Summary of Changes:

  • Move-Grace suppression: Prevent cascade cleanup if a master order move is in progress.
  • Expected Qty Repair: Fixes a gap where expectedPositions were not properly re-asserted after a replacement.
  • Precise Matching: Refines the cascade cleanup signal matching to avoid collateral damage.
  • Build Tag: Incremented to 972.

Summary by CodeRabbit

  • New Features

    • Added automated repair and emergency stop workflows to improve recovery from desynchronization and naked-position risks
    • Added ASCII and dead-code scanning tools and reporting traces for code hygiene
  • Bug Fixes

    • Strengthened follower-order cascade cleanup and matching to prevent state desyncs
    • Defensive expected-position synchronization with rollback on submission failures
    • Preserved pending-cancel specs during meta-purge scenarios
  • Chores

    • Updated build/version tags
    • Expanded infrastructure, deployment, and PR audit protocols and CI audit workflows

Copilot AI review requested due to automatic review settings March 11, 2026 14:02
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds Python analysis tools and policies, updates CI and build tags, introduces REAPER repair and naked-stop processors, enhances follower order/cascade handling with FSM-aware guards and expected-position sync/rollback, and adds various reports, docs, and a new solution file.

Changes

Cohort / File(s) Summary
Docs & Protocols
GEMINI.md, INFRASTRUCTURE_PROTOCOL.md, docs/audits/LIVE_FREEZE_FORENSIC_BRIEF_2026_03_09.md
Added Python extractor protocol, a pre-PR dead-code scan requirement, ghost-process hygiene, deployment/version traceability, and forensic findings about MCP ghost processes.
Python tooling
check_ascii.py, scripts/dead_code_scan.py, scripts/zero_caller_trace.py
New static-analysis utilities: ASCII scanner, dead private-method detector (fails PR on findings), and event/delegate usage tracer (writes trace_results.md).
Scan reports
scripts/build974_findings.txt, scripts/trace_results.md
Added ANTIGRAVITY build scan output and detailed event/delegate trace results for further analysis.
REAPER subsystem
src/V12_002.REAPER.cs, src/V12_002.REAPER.Repair.cs, src/V12_002.REAPER.NakedStop.cs
Removed legacy Reaper audit subsystem and added modular REAPER Repair/NakedStop processors: queues, repair flow, per-account retries, price/market fences, in-flight guards, and cleanup.
Orders & propagation
src/V12_002.Orders.Callbacks.AccountOrders.cs, src/V12_002.Orders.Callbacks.Propagation.cs
Added master-replace detection, META-PURGE guards to preserve PendingCancel specs, FSM-aware cascade skipping, expected-position sync (with rollback on submission failure), and extra logging.
SIMA / State stamps
src/V12_002.SIMA.cs
Stamped account fill grace when expected position set is non-zero; minor restructuring in AddExpectedPositionDeltaLocked.
Build/version constants
src/V12_002.Constants.cs, src/V12_002.cs
Updated Version to "Build 970" and BUILD_TAG to "973" (meta-purge fix note).
Project infra & manifests
universal-or-strategy.sln, tmp_linecounts.txt
Added a Linting solution file and documented many new V12_002.* module partitions.
CI Workflows
.github/workflows/kilo-pr-audit.yml, .github/workflows/codex-audit.yml
Rebranded Gemini→Kilo auditor, swapped model/API usage, hardcoded GCP values, updated mission brief; replaced Python/Aider audit with a JS GitHub Script calling OpenAI in codex-audit.
Auxiliary files
check_ascii.py, scripts/*.txt, scripts/*.md
Added/updated various scan outputs and helper files for analysis and CI guardrails.

Sequence Diagram(s)

sequenceDiagram
    participant Strategy as V12_002 Strategy
    participant RepairQ as ReaperRepairQueue
    participant Repair as ExecuteReaperRepair
    participant Account as Account
    participant Broker as Broker
    participant OrderBook as OrderBook

    Strategy->>RepairQ: Enqueue accountName for repair
    RepairQ->>Repair: Dequeue accountName
    Repair->>Repair: Check flatten in progress / orphan attempts
    alt Orphan attempts > 3
        Repair->>Repair: Force expectedPositions=0
    end
    Repair->>Repair: Compute order type/prices and enforce bounds
    Repair->>Account: CreateOrder(...)
    Account->>Broker: Submit order
    Broker->>OrderBook: Enqueue order
    Repair->>Repair: Clear _repairInFlight and desync tags
Loading
sequenceDiagram
    participant Callback as HandleMatchedFollowerOrder
    participant Cascade as ExecuteFollowerCascadeCleanup
    participant FSM as FSM State
    participant State as ExpectedPositions

    Callback->>Callback: Follower order matched
    alt expectedPositions == 0 and replacementQty != 0
        Callback->>State: Apply META-PURGE guard (preserve PendingCancel)
        Callback->>Callback: Schedule replacement, return (keep FSM)
    else
        Callback->>Cascade: Trigger cascade cleanup
        Cascade->>Cascade: Detect master-replace cancellation?
        alt master-replace detected
            Cascade->>Cascade: Suppress cascade teardown
        else
            Cascade->>FSM: Check for Replace FSM in-flight
            alt Replace FSM in-flight
                Cascade->>Cascade: Skip teardown
            else
                Cascade->>State: Remove ghost refs and sync markers
            end
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

Orders / Callbacks

Poem

🐰
Repairs queued, guards snug and bright,
Cascades tamed by FSM insight,
Scans hum ASCII, dead code flees,
Kilo watches builds and keys—
Build 973 hops into night. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.15% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically describes the main change: a fix for follower order loss during master chart-moves in Build 972, with explicit mention of the two core mechanisms (Move-Grace and REAPER sync).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/follower-loss-fix-b972

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

@deepsource-io
Copy link
Copy Markdown

deepsource-io Bot commented Mar 11, 2026

DeepSource Code Review

We reviewed changes in e8ea4d8...4344889 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 ↗

PR Report Card

Overall Grade  

Focus Area: Reliability
Security  

Reliability  

Complexity  

Hygiene  

Feedback

  • Single giant handler
    • A large handler mixes business logic, branching, and message construction, producing very-high cyclomatic complexity and tangled null/if checks; break it into focused functions and use early-return guards to flatten control flow.
  • Scattered string formatting
    • Inline format templates and manual interpolation are duplicated across code, which easily yields missing-argument runtime errors; centralize message templates or use structured logging/typed format helpers so templates and arguments stay synchronized.
  • Mixed defensive styles
    • Different parts use nested ifs, ternaries, and ad-hoc nullable checks inconsistently, creating redundant and simplifiable conditions; standardize on guard clauses and nullable annotations to remove nesting and make intent explicit.

Code Review Summary

Analyzer Status Updated (UTC) Details
C# Mar 12, 2026 12:26a.m. Review ↗
Secrets Mar 12, 2026 12:26a.m. Review ↗

@github-actions
Copy link
Copy Markdown

🤖 Antigravity Auto-Auditor (Gemini 2.5 Pro via Vertex AI)

Greetings. I am the Gemini CLI, Antigravity Auto-Auditor. I have analyzed this pull request against the GEMINI.md V12 project standards.

My analysis is as follows.

Overall Assessment

The PR introduces critical fixes to the MOVE-SYNC / Follower Order Replace Pattern that correctly address a known race condition (B948-FIX). However, the PR also contains multiple, severe violations of our mandated project standards concerning refactoring and repository hygiene.

Conclusion: Audit FAILED. This PR cannot be merged in its current state.


Part 1: Core Logic Adherence (PASS)

The changes to the follower order FSM and propagation logic are of high quality and correctly adhere to GEMINI.md standards.

  • File: src/V12_002.Orders.Callbacks.AccountOrders.cs

  • Standard: §5. MOVE-SYNC / Follower Order Replace Pattern (Build 947+)

  • Analysis: The modifications to ExecuteFollowerCascadeCleanup are EXEMPLARY.

    • The new method IsMasterReplaceCascadeCancellation and the explicit check for an active FSM spec (_followerReplaceSpecs.TryGetValue) correctly implement a guard ([FSM-GUARD]) to prevent the system from tearing down a follower order that is in the middle of an FSM-controlled replace operation.
    • This precisely closes the race condition where a chart drag/cancel of a master order could cause follower replacement fills to be flagged as CRITICAL DESYNC by REAPER.
  • File: src/V12_002.Orders.Callbacks.Propagation.cs

  • Standard: §5. MOVE-SYNC / Follower Order Replace Pattern (Build 947+) & §Concurrency

  • Analysis: The defensive re-assertion of expectedPositions within SubmitFollowerReplacement is a robust and necessary fix ([B948-FIX-C]).

    • By checking if expectedPositions for the account was zeroed out and re-applying the delta before submission, this change correctly prevents a REAPER desync.
    • The mutation is performed via AddExpectedPositionDeltaLocked, which correctly uses the stateLock guard, satisfying our concurrency standards.

Part 2: Procedural & Hygiene Violations (FAIL)

The PR fails the audit due to the following non-negotiable violations.

VIOLATION 1 (CRITICAL): Banned Manual File Split & Unsanctioned Refactoring

  • Files:
    • src/V12_002.REAPER.cs (logic removed)
    • src/V12_002.REAPER.NakedStop.cs (new file, ~80 lines)
    • src/V12_002.REAPER.Repair.cs (new file, ~200 lines)
  • Standard Violated:
    1. Section 7: Python Extractor Protocol: "ALL file splits MUST use a Python extractor script. Manual copy-paste is BANNED for any split exceeding 50 lines."
    2. §1. Scope Control / Surgical Edits: "AI agents MUST restrict code modifications to the specific files requested in the Mission Brief. NEVER refactor unrelated files without explicit Director authorization."
  • Analysis: The agent performed a large-scale refactoring by extracting over 250 lines of logic from V12_002.REAPER.cs into two new files. This refactoring is out of scope for the stated mission ("B948 Follower Order Loss repair"). Furthermore, the absence of a scripts/<module>_split.py file in this PR indicates this was a manual copy-paste operation, which is strictly forbidden and known to cause silent logic loss.

VIOLATION 2 (SEVERE): Committing Binary and Build Artifacts

  • Files:
    • binary_check.txt (binary)
    • pr_comments.json (binary)
    • scripts/trace_results.txt (binary)
    • universal-or-strategy.sln (project artifact)
    • scripts/build974_findings.txt (build artifact)
    • tmp_linecounts.txt (build artifact)
  • Standard Violated:
    1. §4. Repo Hygiene / Binary Guard: "DO NOT commit .exe, .log, or .bak files." (The spirit of this rule applies to all non-source binary files).
    2. §4. Repo Hygiene / Clean Dashboard: "All agents (...) MUST ensure the repo is clean before starting new missions."
  • Analysis: The PR is polluted with multiple transient files generated during development or analysis. These files do not belong in the repository's history and violate our clean-source policy. The .sln file should be managed by .gitignore, not committed with feature changes.

VIOLATION 3 (NEW STANDARD): Failure to Run Pre-PR Check

  • File: scripts/dead_code_scan.py
  • Standard Violated: §4. Repo Hygiene / Dead Code Prevention: "Before opening any PR, run python scripts/dead_code_scan.py. A FAIL result blocks the PR."
  • Analysis: The PR adds a new standard and the script to enforce it. The presence of analysis files like build974_findings.txt suggests the script was run, and it found 10 private methods with zero callers. However, instead of fixing the dead code, the agent committed the findings. The protocol requires a PASS result from the script before a PR is opened.

Required Actions

  1. Revert the REAPER refactoring. The changes to V12_002.REAPER.cs, V12_002.REAPER.NakedStop.cs, and V12_002.REAPER.Repair.cs must be reverted. This refactoring can be proposed in a separate mission brief that follows the Python Extractor Protocol.
  2. Remove all artifact files. The developer must scrub the PR of all binary files, .sln files, and .txt/.md analysis reports. The branch must be rebased to present a clean history containing only the necessary source and GEMINI.md changes.
  3. Address Dead Code. The methods identified in scripts/build974_findings.txt must be removed if they are truly dead, or the PR must be blocked until they are properly integrated.

This PR will remain blocked until all violations are corrected.

lock (ctx.Sync)
followerEntries = ctx.FollowerEntries.ToArray();

return followerEntries != null && followerEntries.Length > 0;
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.


// Build 935 [R-01]: Handles a follower order positively matched to an active position.
// Entry-not-filled -> rollback + desync label. Entry-filled or stop/target -> ghost log + cleanup.
private void HandleMatchedFollowerOrder(string matchedEntry, PositionInfo matchedPos, Order order, string acctName, string reason)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

HandleMatchedFollowerOrder has a cyclomatic complexity of 43 with "very-high" risk


A function with high cyclomatic complexity can be hard to understand and
maintain. Cyclomatic complexity is a software metric that measures the number of
independent paths through a function. A higher cyclomatic complexity indicates
that the function has more decision points and is more complex.

Comment on lines +406 to +423
if (!string.IsNullOrEmpty(masterEntryName) && dispatchFollowers != null && dispatchFollowers.Length > 0)
{
PositionInfo cascadePos = kvp.Value;
if (!cascadePos.IsFollower) continue;
if (kvp.Key.Contains(orderSignal) || orderSignal.Contains(kvp.Key))
followerKeys = dispatchFollowers;
}
else
{
// Build 948 [FIX-B]: Delimiter-anchored match replaces bidirectional .Contains().
// Bidirectional .Contains() caused accidental cascade of unrelated positions:
// e.g. signal "OR" matched "Fleet_Apex_RETEST_OR_1" incidentally.
// Anchoring on underscores prevents substring contamination across signal families.
followerKeys = snapshot
.Where(kvp => kvp.Value != null && kvp.Value.IsFollower
&& (kvp.Key == orderSignal
|| kvp.Key.Contains("_" + orderSignal + "_")
|| kvp.Key.EndsWith("_" + orderSignal)))
.Select(kvp => kvp.Key)
.ToArray();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

If-else statement can be simplified


Both the then and else blocks of the if statement contain only assignment expressions and these assignment expressions refer to the same identifier. Such statements can be rewritten using the ternary operator.

Print($"[REAPER] REPAIR BLOCKED: Price fence exceeded for {accountName}. " +
$"Current={currentPrice:F2}, Entry={repairEntryPrice:F2}, " +
$"Diff={priceDiff:F4} > Fence={fenceDistance:F4} ({RepairTickFence} ticks). " +
$"Adjust RepairTickFence if you want to force entry.");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing arguments to the interpolated text


String interpolation requires that you specify the string that is to be interpolated and the required arguments. Failing to specify the required arguments may result in an ill-formatted string. Because it is possible that such strings can critically alter the behaviour and control-flow of the program, it is suggested that you fix it as soon as possible.

if (currentExpected == 0)
{
Print($"[REAPER REPAIR] (!) RACE GUARD ABORT for {accountName}: " +
$"expectedPositions cleared to 0 while repair was in queue. Discarding repair order.");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing arguments to the interpolated text


String interpolation requires that you specify the string that is to be interpolated and the required arguments. Failing to specify the required arguments may result in an ill-formatted string. Because it is possible that such strings can critically alter the behaviour and control-flow of the program, it is suggested that you fix it as soon as possible.

@github-actions
Copy link
Copy Markdown

────────────────────────────────────────────────────────────────────────────────
Update git name with: git config user.name "Your Name"
Update git email with: git config user.email "you@example.com"
You can skip this check with --no-gitignore
Added .aider* to .gitignore
Aider v0.86.2
Main model: gpt-4o with diff edit format
Weak model: gpt-4o-mini
Git repo: .git with 308 files
Repo-map: using 4096 tokens, auto refresh

https://aider.chat/HISTORY.html#release-notes

Initial repo scan can be slow in larger repos, but only happens once.
Repo-map can't include
/home/runner/work/universal-or-strategy/universal-or-strategy/.claude/worktrees/
affectionate-franklin
Has it been deleted from the file system but not from git?
Repo-map can't include
/home/runner/work/universal-or-strategy/universal-or-strategy/.claude/worktrees/
sleepy-jepsen
Has it been deleted from the file system but not from git?
Repo-map can't include
/home/runner/work/universal-or-strategy/universal-or-strategy/AntigravityMobile
Has it been deleted from the file system but not from git?
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 0.2 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 0.5 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 1.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 2.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 4.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 8.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 16.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 32.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.

https://platform.openai.com/docs/guides/error-codes/api-errors

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 11, 2026

Greptile Summary

This PR implements three targeted fixes for the Build 948 incident where follower orders were lost when a master chart-order was moved (dragged), plus a REAPER partial-class split for file-size compliance.

Core fixes:

  • FIX-A (Move-Grace suppression): ExecuteFollowerCascadeCleanup now checks IsMasterReplaceCascadeCancellation before tearing down followers. If a master replace is in progress, the cascade is fully suppressed; per-follower FSM guards additionally protect individual in-flight replacements in the followerKeys loop.
  • FIX-B (Precise signal matching): Replaces bidirectional .Contains() with delimiter-anchored matching (_signal_ / _signal suffix) to prevent unrelated positions (e.g., Fleet_Apex_RETEST_OR_1) from being accidentally cascaded when a short signal name like OR is cancelled.
  • FIX-C (Expected qty re-assertion): SubmitFollowerReplacement now re-asserts expectedPositions before submitting the replacement order if the cascade concurrently zeroed it, preventing a false REAPER Critical Desync → Emergency Flatten.
  • REAPER split: ExecuteReaperRepair, ProcessReaperNakedStopQueue, and audit methods are extracted into REAPER.Repair.cs / REAPER.NakedStop.cs partial-class files (verbatim, no logic change).

Issues found:

  • Logic bug: In SubmitFollowerReplacement, FIX-C's re-assertion block and the new expectedDelta qty-diff block can both fire in the same invocation when expectedPositions was zeroed AND the replacement qty differs from trackedPos.TotalContracts, causing a double-increment of expectedPositions.
  • Version mismatch: BUILD_TAG is "972" but Constants.Version is "Build 970" — two-build discrepancy will produce inconsistent diagnostic logs.
  • Artifact files committed: binary_check.txt, pr_comments.json, scripts/trace_results.txt, scripts/trace_results.md, and tmp_linecounts.txt are transient work artifacts that should be .gitignored or removed.
  • Hardcoded paths: scripts/zero_caller_trace.py uses absolute c:\WSGTA\... paths, making it non-portable. scripts/dead_code_scan.py (added in the same PR) correctly uses relative paths as the model.

Confidence Score: 3/5

  • The core cascade-suppression logic is sound but a double-increment bug in SubmitFollowerReplacement could produce false REAPER desyncs in edge cases; artifact files and version mismatch should be cleaned up before merging.
  • The three FIX-A/B/C patches address the described Build 948 race condition correctly in the common case. However, FIX-C's re-assertion block and the new expectedDelta qty-diff block in SubmitFollowerReplacement are not mutually exclusive — a concurrent cascade-zero plus a quantity-change replacement will double-increment expectedPositions, potentially triggering the very REAPER desync the PR is trying to prevent. This is a medium-severity logic bug that warrants a fix before merge. The REAPER partial-class split is verbatim and carries no risk. The version mismatch (972 vs "Build 970") and committed artifact files are minor housekeeping issues.
  • src/V12_002.Orders.Callbacks.Propagation.cs (double expectedPositions increment risk), src/V12_002.Orders.Callbacks.AccountOrders.cs (cascade suppression scope), src/V12_002.Constants.cs (version mismatch)

Important Files Changed

Filename Overview
src/V12_002.Orders.Callbacks.Propagation.cs FIX-C defensive re-assertion of expectedPositions before replacement submit, plus new try/catch around acct.Submit with rollback. Contains a logic bug where FIX-C re-assertion and the new expectedDelta block can both fire simultaneously and double-increment expectedPositions for the same account key.
src/V12_002.Orders.Callbacks.AccountOrders.cs Core cascade cleanup refactor: new IsMasterReplaceCascadeCancellation helper suppresses full cascade for master replace events; delimiter-anchored signal matching (FIX-B) replaces fragile bidirectional Contains(); per-follower FSM guard (FIX-A) skips teardown for in-flight replacements. Top-level early-return may over-suppress when only a subset of followers has an active FSM.
src/V12_002.SIMA.cs AddOrUpdateExpectedPositionLocked now stamps per-account fill grace whenever expectedPositions is set to a non-zero value, ensuring REAPER suppresses false desync checks after replacements.
src/V12_002.REAPER.cs Large deletion: ProcessReaperRepairQueue, ExecuteReaperRepair, ProcessReaperNakedStopQueue, AuditSingleFleetAccount, AuditMasterAccountIfNeeded, ProcessReaperFlattenQueue all extracted to separate partial-class files (REAPER.Repair.cs, REAPER.NakedStop.cs, REAPER.Audit.cs) as part of CS-R1140 file-size compliance split. Logic is preserved verbatim.
src/V12_002.REAPER.Repair.cs New partial-class file containing ProcessReaperRepairQueue and ExecuteReaperRepair, extracted verbatim from REAPER.cs. Logic is identical to the deleted code; no behavioral change.
src/V12_002.REAPER.NakedStop.cs New partial-class file containing ProcessReaperNakedStopQueue, extracted verbatim from REAPER.cs. No behavioral change.
src/V12_002.cs BUILD_TAG bumped from "967" to "972"; however Constants.Version in V12_002.Constants.cs is only bumped to "Build 970" — a two-build discrepancy that will produce inconsistent diagnostics.
src/V12_002.Constants.cs Version string bumped to "Build 970" while BUILD_TAG in V12_002.cs is "972"; these two version identifiers are out of sync.
scripts/dead_code_scan.py New CI-gate script that statically scans private methods for zero callers, with delegate/event-wiring exemptions. Uses portable relative paths correctly; logic is sound for its stated purpose.
scripts/zero_caller_trace.py Event/delegate trace helper with hardcoded absolute Windows paths (c:\WSGTA...) that will fail on any other machine or CI environment; should use relative paths like dead_code_scan.py does.
binary_check.txt Temporary work artifact (binary) committed to the repository alongside pr_comments.json, scripts/trace_results.txt, and tmp_linecounts.txt — none of these belong in version control.

Sequence Diagram

sequenceDiagram
    participant Chart as Chart Drag
    participant AOC as AccountOrders Callback
    participant FSM as FollowerReplaceSpec FSM
    participant Prop as SubmitFollowerReplacement
    participant Fleet as Fleet Account
    participant REAPER as REAPER Audit

    Chart->>AOC: OnAccountOrderUpdate (Cancelled)
    AOC->>AOC: IsMasterReplaceCascadeCancellation?
    alt Any follower FSM is PendingCancel or Submitting
        AOC-->>AOC: Suppress cascade entirely (FIX-A)
    else No active FSM
        AOC->>AOC: Build followerKeys - delimiter-anchored match (FIX-B)
        loop Each followerKey
            alt In-flight Replace FSM exists
                AOC-->>AOC: Skip this follower (FIX-A per-follower guard)
            else No FSM
                AOC->>AOC: CleanupPosition + DeltaExpectedPositionLocked
            end
        end
    end

    Note over AOC,FSM: Follower cancel triggers replacement flow
    AOC->>FSM: State = Submitting
    FSM->>Prop: TriggerCustomEvent to submit replacement
    Prop->>Prop: FIX-C - if expectedPositions==0 re-assert qty
    Prop->>Prop: Compute expectedDelta from qty diff
    Prop->>Fleet: acct.Submit(newEntry)
    alt Submit succeeds
        Fleet-->>Prop: OK
        Prop->>REAPER: StampAccountFillGrace via SIMA delta update
        REAPER-->>REAPER: Suppress desync check during grace window
    else Submit throws
        Prop->>Prop: Rollback expectedDelta
    end
Loading

Comments Outside Diff (4)

  1. src/V12_002.Orders.Callbacks.Propagation.cs, line 806-844 (link)

    Double expectedPositions increment when FIX-C re-assertion and expectedDelta both fire

    Two separate blocks in SubmitFollowerReplacement can both add to expectedPositions for the same account key in the same invocation. FIX-C (lines 809–816) re-asserts qty when _b948CurrentExp == 0. Immediately after, the expectedDelta block (lines 824–829) adds another delta based on qty - trackedPos.TotalContracts.

    If expectedPositions was zeroed by a cascade race and the replacement qty differs from trackedPos.TotalContracts, both conditions are true simultaneously:

    1. FIX-C adds qtyexpectedPositions[key] = qty
    2. expectedDelta = qty - trackedPos.TotalContracts is also non-zero → adds again

    Result: expectedPositions[key] = 2*qty - trackedPos.TotalContracts instead of the correct qty. This would cause REAPER to see a false desync and trigger unnecessary repair or emergency flatten.

    The simplest guard is to zero out expectedDelta when FIX-C fires:

    int expectedDelta = 0;
    PositionInfo trackedPos;
    // FIX-C already set expectedPositions to `qty`; skip qty-diff adjustment to avoid double-add.
    bool b948Reasserted = (_b948CurrentExp == 0 && qty != 0);
    if (!b948Reasserted && activePositions.TryGetValue(fleetSignalName, out trackedPos) && trackedPos != null)
    {
        int qtyDiff = qty - trackedPos.TotalContracts;
        if (qtyDiff != 0)
            expectedDelta = trackedPos.Direction == MarketPosition.Long ? qtyDiff : -qtyDiff;
    }
  2. scripts/zero_caller_trace.py, line 491-492 (link)

    Hardcoded machine-specific paths break portability

    Both src_dir and root_dir are absolute Windows paths tied to a single developer machine. Any other contributor (or CI runner) will get an immediate FileNotFoundError / wrong-directory scan.

    Use a path relative to the script's own location — the same pattern already used in dead_code_scan.py:

  3. binary_check.txt, line 1 (link)

    Temporary/artifact files committed to the repository

    This PR includes several files that appear to be transient work artifacts and should not be tracked in version control:

    • binary_check.txt (binary file, ad-hoc check output)
    • pr_comments.json (binary file, agent workflow artifact)
    • scripts/trace_results.txt (binary file, script output)
    • scripts/trace_results.md (script output — event/delegate scan results)
    • tmp_linecounts.txt (temporary line-count snapshot)

    The GEMINI.md Binary Guard rule ("DO NOT commit .exe, .log, or .bak files") reflects the principle of keeping the repo clean of ephemeral outputs. These files should either be added to .gitignore or removed from this PR before merging.

  4. src/V12_002.Orders.Callbacks.AccountOrders.cs, line 602-638 (link)

    IsMasterReplaceCascadeCancellation suppresses entire cascade when only a subset of followers has an active FSM

    When the method returns true (line 676), the caller does a full return, skipping cascade cleanup for all followers — including any that do not have an active Replace FSM spec. The intent of FIX-A is to protect in-flight replacements, but followers in neutral state are also skipped as collateral.

    In the common single-follower case this is fine. In a multi-follower dispatch where one follower is being replaced and another is genuinely orphaned (e.g., broker rejected its original order but no FSM was started), the orphaned follower will not be cleaned up during this cancel event.

    The per-follower [FSM-GUARD] check in the followerKeys loop handles the same guard at a finer granularity — consider whether the top-level early-return is still needed, or whether it should only fire when all dispatch followers have an active FSM.

Last reviewed commit: 6ac938d

Comment thread src/V12_002.cs Outdated
public partial class V12_002 : Strategy
{
public const string BUILD_TAG = "967"; // V12.967: Freeze Shield -- IPC stall elimination [B967-FIX-01][B967-FIX-02]
public const string BUILD_TAG = "972"; // V12.972: B948 Follower Order Loss repair [B948-FIX-A][B948-FIX-B][B948-FIX-C]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

BUILD_TAG / Constants.Version mismatch

BUILD_TAG is "972" here, but Constants.Version in V12_002.Constants.cs was only bumped to "Build 970". These two values are presumably both printed in diagnostics and heartbeat logs. Having them differ by two build numbers will cause confusion when reading logs.

Suggested change
public const string BUILD_TAG = "972"; // V12.972: B948 Follower Order Loss repair [B948-FIX-A][B948-FIX-B][B948-FIX-C]
public const string BUILD_TAG = "972"; // V12.972: B948 Follower Order Loss repair [B948-FIX-A][B948-FIX-B][B948-FIX-C]

V12_002.Constants.cs should be updated to "Build 972" to match.

Copy link
Copy Markdown

@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: 12

🧹 Nitpick comments (3)
scripts/dead_code_scan.py (2)

76-82: Consider expanding delegate detection patterns.

The current patterns cover +=, new Thread(), new ThreadStart(), and TriggerCustomEvent(). Consider adding:

  • new Action(Name) / new Func<...>(Name) — common delegate instantiation
  • EventHandler patterns
  • Lambda references (harder to detect statically)

This would reduce false positives for methods passed as delegates to framework or custom event systems.

Extended pattern suggestion
         delegate_pat = re.compile(
             r'(?:\+\=\s*' + re.escape(name) + r'\b'
             r'|new\s+Thread\s*\(\s*' + re.escape(name) + r'\s*\)'
             r'|new\s+ThreadStart\s*\(\s*' + re.escape(name) + r'\s*\)'
             r'|TriggerCustomEvent\s*\(\s*' + re.escape(name) + r'\s*\)'
+            r'|new\s+Action\s*\(\s*' + re.escape(name) + r'\s*\)'
+            r'|new\s+EventHandler\s*\(\s*' + re.escape(name) + r'\s*\)'
             r')'
         )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/dead_code_scan.py` around lines 76 - 82, The delegate detection regex
(delegate_pat) is too narrow and misses common delegate instantiations; update
delegate_pat to also match patterns like new Action(Name), new Func<...>(Name),
new\s+EventHandler(Name) and generic Func/Action forms so methods passed as
delegates aren't flagged as dead (use re.escape(name) in each alternative just
like the existing ones); optionally add alternates for nameof usage or method
group conversions if feasible, and keep the overall grouping and word-boundary
handling consistent with the existing patterns.

69-74: Address style issues: multiple statements on single lines.

Per Ruff static analysis, lines 69, 71, 74, and 89 have multiple statements on one line (colon pattern). While functional, this reduces readability.

Suggested style fix
-            if stripped.startswith('//'): continue
+            if stripped.startswith('//'):
+                continue
             if call_pat2.search(line):
-                if fname2 == fname and i == lineno: continue  # skip own decl
+                if fname2 == fname and i == lineno:
+                    continue  # skip own decl
                 call_found = True
                 break
-        if call_found: break
+        if call_found:
+            break

And line 89:

-            if call_found: break
+            if call_found:
+                break

Also applies to: 89-89

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/dead_code_scan.py` around lines 69 - 74, The code has multiple simple
statements combined on single lines (e.g., "if stripped.startswith('//'):
continue", "if fname2 == fname and i == lineno: continue  # skip own decl", and
"if call_found: break") which Ruff flags; update scripts/dead_code_scan.py to
expand these into normal if-blocks so each conditional and its action are on
separate lines—locate uses of stripped.startswith, the call_pat2.search block,
the fname2/fname/i/lineno self-decl check, and the call_found check and rewrite
them to use standard multi-line if statements for readability and stylistic
compliance.
check_ascii.py (1)

3-8: Consider scanning all C# files dynamically.

The hardcoded file list will miss new files added to src/. Consider using glob or os.walk to scan all .cs files:

Suggested improvement
-files = [
-    'src/V12_002.REAPER.cs',
-    'src/V12_002.SIMA.cs',
-    'src/V12_002.cs',
-    'src/V12_002.Orders.Callbacks.cs'
-]
+import glob
+
+files = glob.glob('src/**/*.cs', recursive=True)
+if not files:
+    print("No .cs files found in src/")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@check_ascii.py` around lines 3 - 8, The hardcoded files list in
check_ascii.py (the files variable) will miss newly added C# files; replace it
with a dynamic scanner (e.g., use glob.glob('src/**/*.cs', recursive=True) or
os.walk to collect all .cs paths under src/) and assign the resulting list to
files so the script automatically includes any new or nested .cs files; update
any downstream code that iterates over files to work with the new list format.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/build974_findings.txt`:
- Around line 6-16: The dead-code scanner is flagging event handlers and thread
entry points as "zero callers"; update dead_code_scan.py to detect C# delegate
subscription patterns (e.g., "+=" assignments such as acct.ExecutionUpdate +=
OnAccountExecutionUpdate and ChartControl.PreviewMouseLeftButtonDown +=
OnChartClick) and thread start constructions (e.g., new Thread(ReaperLoop) or
new Thread(new ThreadStart(ListenForRemote))) as valid callers so methods like
OnAccountExecutionUpdate, OnAccountOrderUpdate, OnChartClick, OnKeyDown,
ReaperLoop and ListenForRemote are not reported as dead; also add logic to
suppress or re-verify reported methods that no longer exist (e.g.,
OnBreakevenButtonClick) so stale entries are ignored rather than flagged.

In `@scripts/dead_code_scan.py`:
- Around line 14-21: NT8_LIFECYCLE whitelist is missing account-level handlers
which causes false positives; update the NT8_LIFECYCLE set to include the two
account event handler names 'OnAccountOrderUpdate' and
'OnAccountExecutionUpdate' so the dead-code scanner recognizes methods wired via
Account.OrderUpdate and Account.ExecutionUpdate; locate the NT8_LIFECYCLE
constant and append those two symbol strings to the set, preserving the existing
formatting and commas.

In `@scripts/zero_caller_trace.py`:
- Around line 45-46: The except Exception as e: pass silently swallows scan
failures; replace it so the failing file path and exception are surfaced and the
run fails: in scripts/zero_caller_trace.py locate the except block (the except
Exception as e handler) and either log the error with full context (e.g.,
logging.exception or processLogger.error including the file path variable) and
then re-raise the exception or call sys.exit(1) to fail the run; ensure the log
message includes the path being scanned and the exception message/traceback so
the report is not misleading.
- Around line 17-18: Replace hard-coded Windows absolute paths by deriving the
repo root from __file__ and building paths with pathlib: compute root_dir =
Path(__file__).resolve().parent.parent (or the appropriate parent to reach the
repository root), set src_dir = root_dir / "src" and use root_dir /
"trace_results.md" when opening/writing the output; update the other occurrence
around line 48 the same way so all scan/write paths are repository-relative and
platform-independent.
- Around line 34-44: The matcher is counting occurrences inside comments and
string literals; before testing each line for candidates (the code that uses
variables cand, match, results, path, line), strip/ignore comments and string
literals first (remove //... and /*...*/ spans and quoted strings including
escaped quotes and verbatim @"..." forms) or operate on a preprocessed version
of the file content, then run the existing regex search r'\b' + cand +
r'\b(?!\s*\()' and the override check; update the logic around the match/results
append so only matches from code (not comments or string literals) are recorded.

In `@src/V12_002.Constants.cs`:
- Line 12: The Version constant (public const string Version in
src/V12_002.Constants.cs) is out of sync with BUILD_TAG in V12_002.cs; update
the Version string to match BUILD_TAG (change "Build 970" to "Build 972") or
adjust both to the intended build identifier so they are consistent, ensuring
any consumers of V12_002.Constants.Version and the BUILD_TAG value reflect the
same build number.

In `@src/V12_002.Orders.Callbacks.Propagation.cs`:
- Around line 447-455: When re-asserting expectedPositions in the replacement
path (when _b948CurrentExp == 0 and qty != 0) collapse the two adjustments into
a single signed delta: compute the netDelta using spec.EntryAction to determine
sign (buy = +, sell = -) that accounts for both the re-asserted qty and the
subsequent qty-sync, then call
AddExpectedPositionDeltaLocked(ExpKey(accountName), netDelta) once, followed by
MarkDispatchSyncPending(...) and the Print(...) call; apply the same change to
the other similar block (lines 462-483) so you do not double-apply exposure
deltas to expectedPositions.
- Around line 486-489: Re-check the master's filled state immediately before
submitting instead of unconditionally calling acct.Submit(new[] { newEntry
});—evaluate the current masterFilled condition (or call the same helper used
earlier to determine master fill) and if the master is now filled, route this
account/entry into the REAPER repair flow (invoke the project's REAPER repair
handler) rather than calling acct.Submit; only call acct.Submit(new[] { newEntry
}) when the re-checked masterFilled is false.

In `@src/V12_002.REAPER.NakedStop.cs`:
- Around line 62-63: The current code clears the naked-stop guard immediately
after Submit by calling
_reaperNakedStopInFlight.TryRemove(ExpKey(item.AccountName)), which allows the
naked-position detector to requeue the same account before the broker
acknowledges the stop; instead, remove the TryRemove call here and move
guard-clear logic into the order/update acknowledgement path (the code that
processes broker order confirmations/updates), ensuring _reaperNakedStopInFlight
is only cleared when a working stop or broker acknowledgment for the submitted
stop is observed; update references to ExpKey(item.AccountName) in that
acknowledgement handler so the guard is removed reliably and duplicates cannot
be enqueued.

In `@src/V12_002.REAPER.Repair.cs`:
- Around line 174-179: The code sets repairPos.BracketSubmitted = false and
entryOrders[repairEntryName] = repairEntry before calling targetAcct.Submit,
which can leave strategy state inconsistent if Submit throws; move the
entryOrders[repairEntryName] = repairEntry and the mutation of
repairPos.BracketSubmitted so they occur only after targetAcct.Submit completes
successfully, and wrap the repairPos mutation (and any other state mutations
such as activePositions/expectedPositions or entryOrders) inside lock(stateLock)
to satisfy the "All state mutations ... MUST be guarded by lock(stateLock)"
guideline; keep targetAcct.Submit outside the lock and ensure exceptions prevent
the state update.
- Around line 58-64: The current code force-zeroes expected positions via
SetExpectedPositionLocked(ExpKey(accountName), 0) which violates the
signed-delta rollback rule; instead, fetch the current expected value (e.g.,
GetExpectedPositionLocked(ExpKey(accountName)) or lookup
_expectedPositions[ExpKey(accountName)]), fetch the actual account
position/PositionInfo for accountName (e.g., GetAccountPosition(accountName) or
PositionInfo lookup), compute signedDelta = actualPosition - currentExpected,
and apply a signed rollback/reconcile (either by calling an existing
ApplySignedDelta/AdjustExpectedPosition method or by calling
SetExpectedPositionLocked(ExpKey(accountName), currentExpected + signedDelta))
only when signedDelta != 0; then remove the entry from _reaperOrphanRepairCount
as before. Ensure you do not blanket-zero expected positions and that the
reconcile uses the signed delta derived from currentExpected and actualPosition.

In `@src/V12_002.SIMA.cs`:
- Around line 85-89: Calls to StampAccountFillGrace are passing raw accountName
but the method and lookup use a composite expKey; update both calls (the ones
shown and the later call at line ~114) to construct and pass the same composite
key used by IsReaperFillGraceActive and the _accountFillGraceTicks map (e.g.,
call ExpKey(accountName, instrument) or the project's composite key helper) so
the stored and queried keys match; ensure you reference and use the same
key-construction helper/function used elsewhere so StampAccountFillGrace
receives the correct expKey.

---

Nitpick comments:
In `@check_ascii.py`:
- Around line 3-8: The hardcoded files list in check_ascii.py (the files
variable) will miss newly added C# files; replace it with a dynamic scanner
(e.g., use glob.glob('src/**/*.cs', recursive=True) or os.walk to collect all
.cs paths under src/) and assign the resulting list to files so the script
automatically includes any new or nested .cs files; update any downstream code
that iterates over files to work with the new list format.

In `@scripts/dead_code_scan.py`:
- Around line 76-82: The delegate detection regex (delegate_pat) is too narrow
and misses common delegate instantiations; update delegate_pat to also match
patterns like new Action(Name), new Func<...>(Name), new\s+EventHandler(Name)
and generic Func/Action forms so methods passed as delegates aren't flagged as
dead (use re.escape(name) in each alternative just like the existing ones);
optionally add alternates for nameof usage or method group conversions if
feasible, and keep the overall grouping and word-boundary handling consistent
with the existing patterns.
- Around line 69-74: The code has multiple simple statements combined on single
lines (e.g., "if stripped.startswith('//'): continue", "if fname2 == fname and i
== lineno: continue  # skip own decl", and "if call_found: break") which Ruff
flags; update scripts/dead_code_scan.py to expand these into normal if-blocks so
each conditional and its action are on separate lines—locate uses of
stripped.startswith, the call_pat2.search block, the fname2/fname/i/lineno
self-decl check, and the call_found check and rewrite them to use standard
multi-line if statements for readability and stylistic compliance.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 21225955-80fa-4a69-bded-f9e4e3957503

📥 Commits

Reviewing files that changed from the base of the PR and between e8ea4d8 and 6ac938d.

📒 Files selected for processing (19)
  • GEMINI.md
  • binary_check.txt
  • check_ascii.py
  • pr_comments.json
  • scripts/build974_findings.txt
  • scripts/dead_code_scan.py
  • scripts/trace_results.md
  • scripts/trace_results.txt
  • scripts/zero_caller_trace.py
  • src/V12_002.Constants.cs
  • src/V12_002.Orders.Callbacks.AccountOrders.cs
  • src/V12_002.Orders.Callbacks.Propagation.cs
  • src/V12_002.REAPER.NakedStop.cs
  • src/V12_002.REAPER.Repair.cs
  • src/V12_002.REAPER.cs
  • src/V12_002.SIMA.cs
  • src/V12_002.cs
  • tmp_linecounts.txt
  • universal-or-strategy.sln
💤 Files with no reviewable changes (1)
  • src/V12_002.REAPER.cs

Comment on lines +6 to +16
--- ZERO CALLERS (highest priority) ---
METHOD=ExecuteRMAEntry FILE=V12_002.Entries.RMA.cs LINE=185
METHOD=ExecuteRMAEntryCustom FILE=V12_002.Entries.RMA.cs LINE=356
METHOD=HandleExternalSignal FILE=V12_002.UI.IPC.cs LINE=220
METHOD=ListenForRemote FILE=V12_002.UI.IPC.Server.cs LINE=65
METHOD=OnAccountExecutionUpdate FILE=V12_002.UI.Compliance.cs LINE=273
METHOD=OnAccountOrderUpdate FILE=V12_002.Orders.Callbacks.AccountOrders.cs LINE=37
METHOD=OnBreakevenButtonClick FILE=V12_002.Trailing.Breakeven.cs LINE=35
METHOD=OnChartClick FILE=V12_002.UI.Callbacks.cs LINE=76
METHOD=OnKeyDown FILE=V12_002.UI.Callbacks.cs LINE=172
METHOD=ReaperLoop FILE=V12_002.REAPER.cs LINE=122
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if these methods are wired as delegates/event handlers
echo "=== Checking delegate wiring for flagged methods ==="
for method in OnAccountExecutionUpdate OnAccountOrderUpdate OnBreakevenButtonClick OnChartClick OnKeyDown ReaperLoop ListenForRemote; do
    echo "--- $method ---"
    rg -n "\+\=\s*$method|new\s+Thread\s*\(\s*$method|ThreadStart\s*\(\s*$method" src/ || echo "No delegate wiring found"
done

Repository: mkalhitti-cloud/universal-or-strategy

Length of output: 1655


🏁 Script executed:

#!/bin/bash
# Check if these methods are wired as delegates/event handlers
echo "=== Checking delegate wiring for flagged methods ==="
for method in OnAccountExecutionUpdate OnAccountOrderUpdate OnBreakevenButtonClick OnChartClick OnKeyDown ReaperLoop ListenForRemote; do
    echo "--- $method ---"
    # Search for += method_name (delegate assignment)
    rg -n "\+= *$method" src/ && echo "Found delegate assignment" || true
    # Search for new Thread(method_name)
    rg -n "new Thread.*$method" src/ && echo "Found Thread usage" || true
    # Search for ThreadStart
    rg -n "ThreadStart.*$method" src/ && echo "Found ThreadStart usage" || true
done

Repository: mkalhitti-cloud/universal-or-strategy

Length of output: 1018


🏁 Script executed:

#!/bin/bash
# Check OnBreakevenButtonClick for any wiring or usage
echo "=== Checking OnBreakevenButtonClick ==="
rg -n "OnBreakevenButtonClick" src/ -B 2 -A 2

Repository: mkalhitti-cloud/universal-or-strategy

Length of output: 120


🏁 Script executed:

#!/bin/bash
# Check if the Breakeven file exists and what's at line 35
echo "=== Finding Breakeven file ==="
find src/ -name "*Breakeven*" -type f
echo ""
echo "=== Content around line 35 ==="
head -40 src/V12_002.Trailing.Breakeven.cs | tail -10

Repository: mkalhitti-cloud/universal-or-strategy

Length of output: 419


🏁 Script executed:

#!/bin/bash
# Read exact content at line 35
echo "=== Lines 30-40 of Breakeven.cs ==="
sed -n '30,40p' src/V12_002.Trailing.Breakeven.cs
echo ""
echo "=== Searching for any method definitions ==="
rg -n "^\s*(public|private|protected).*OnBreakeven" src/V12_002.Trailing.Breakeven.cs

Repository: mkalhitti-cloud/universal-or-strategy

Length of output: 405


Six of the listed "zero caller" methods are false positives — they are wired as event handlers or thread entry points.

Confirmed delegate/thread wiring:

  • OnAccountExecutionUpdate — wired via acct.ExecutionUpdate += (V12_002.SIMA.Lifecycle.cs:120)
  • OnAccountOrderUpdate — wired via acct.OrderUpdate += (V12_002.SIMA.Lifecycle.cs:121)
  • OnChartClick — wired via ChartControl.PreviewMouseLeftButtonDown += (V12_002.UI.Callbacks.cs:59)
  • OnKeyDown — wired via ChartControl.OwnerChart.PreviewKeyDown += (V12_002.UI.Callbacks.cs:43)
  • ReaperLoop — passed to new Thread() (V12_002.REAPER.cs:91)
  • ListenForRemote — passed to new Thread() (V12_002.UI.IPC.Server.cs:52)

The dead code scanner is missing standard C# delegate assignment patterns (+=) and thread constructor calls. Update dead_code_scan.py to recognize these patterns. Additionally, OnBreakevenButtonClick does not appear to exist in the current codebase and may be a stale entry from the scan.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/build974_findings.txt` around lines 6 - 16, The dead-code scanner is
flagging event handlers and thread entry points as "zero callers"; update
dead_code_scan.py to detect C# delegate subscription patterns (e.g., "+="
assignments such as acct.ExecutionUpdate += OnAccountExecutionUpdate and
ChartControl.PreviewMouseLeftButtonDown += OnChartClick) and thread start
constructions (e.g., new Thread(ReaperLoop) or new Thread(new
ThreadStart(ListenForRemote))) as valid callers so methods like
OnAccountExecutionUpdate, OnAccountOrderUpdate, OnChartClick, OnKeyDown,
ReaperLoop and ListenForRemote are not reported as dead; also add logic to
suppress or re-verify reported methods that no longer exist (e.g.,
OnBreakevenButtonClick) so stale entries are ignored rather than flagged.

Comment thread scripts/dead_code_scan.py
Comment on lines +14 to +21
NT8_LIFECYCLE = {
'OnStateChange','OnBarUpdate','OnOrderUpdate','OnPositionUpdate',
'OnExecutionUpdate','OnAccountOrderUpdate','OnConnectionStatusUpdate',
'OnMarketData','OnRender','OnRestoreValues','OnMarketDepth',
'OnWindowCreated','OnWindowDestroyed','OnMouseClick','OnMouseMove',
'OnKeyUp','OnKeyDown','CreateWPFControls','DestroyWPFControls',
'Initialize','Dispose','ToString','GetHashCode','Equals','Finalize',
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Expand NT8_LIFECYCLE whitelist to include account event handlers.

The whitelist is missing common NinjaTrader account-level event handlers that are wired externally:

  • OnAccountOrderUpdate — wired to Account.OrderUpdate
  • OnAccountExecutionUpdate — wired to Account.ExecutionUpdate

This omission causes false positives in the scan results (see build974_findings.txt).

Suggested fix
 NT8_LIFECYCLE = {
     'OnStateChange','OnBarUpdate','OnOrderUpdate','OnPositionUpdate',
     'OnExecutionUpdate','OnAccountOrderUpdate','OnConnectionStatusUpdate',
+    'OnAccountExecutionUpdate',
     'OnMarketData','OnRender','OnRestoreValues','OnMarketDepth',
     'OnWindowCreated','OnWindowDestroyed','OnMouseClick','OnMouseMove',
     'OnKeyUp','OnKeyDown','CreateWPFControls','DestroyWPFControls',
     'Initialize','Dispose','ToString','GetHashCode','Equals','Finalize',
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
NT8_LIFECYCLE = {
'OnStateChange','OnBarUpdate','OnOrderUpdate','OnPositionUpdate',
'OnExecutionUpdate','OnAccountOrderUpdate','OnConnectionStatusUpdate',
'OnMarketData','OnRender','OnRestoreValues','OnMarketDepth',
'OnWindowCreated','OnWindowDestroyed','OnMouseClick','OnMouseMove',
'OnKeyUp','OnKeyDown','CreateWPFControls','DestroyWPFControls',
'Initialize','Dispose','ToString','GetHashCode','Equals','Finalize',
}
NT8_LIFECYCLE = {
'OnStateChange','OnBarUpdate','OnOrderUpdate','OnPositionUpdate',
'OnExecutionUpdate','OnAccountOrderUpdate','OnConnectionStatusUpdate',
'OnAccountExecutionUpdate',
'OnMarketData','OnRender','OnRestoreValues','OnMarketDepth',
'OnWindowCreated','OnWindowDestroyed','OnMouseClick','OnMouseMove',
'OnKeyUp','OnKeyDown','CreateWPFControls','DestroyWPFControls',
'Initialize','Dispose','ToString','GetHashCode','Equals','Finalize',
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/dead_code_scan.py` around lines 14 - 21, NT8_LIFECYCLE whitelist is
missing account-level handlers which causes false positives; update the
NT8_LIFECYCLE set to include the two account event handler names
'OnAccountOrderUpdate' and 'OnAccountExecutionUpdate' so the dead-code scanner
recognizes methods wired via Account.OrderUpdate and Account.ExecutionUpdate;
locate the NT8_LIFECYCLE constant and append those two symbol strings to the
set, preserving the existing formatting and commas.

Comment on lines +17 to +18
src_dir = r"c:\WSGTA\universal-or-strategy\src"
root_dir = r"c:\WSGTA\universal-or-strategy"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Make the scan paths repository-relative.

These absolute c:\WSGTA\... paths make the script unusable anywhere except one workstation. Derive the repo root from __file__ and write trace_results.md relative to that path.

Suggested fix
 import os
 import re
+from pathlib import Path
@@
-src_dir = r"c:\WSGTA\universal-or-strategy\src"
-root_dir = r"c:\WSGTA\universal-or-strategy"
+ROOT_DIR = Path(__file__).resolve().parents[1]
+SRC_DIR = ROOT_DIR / "src"
@@
-    for root, dirs, files in os.walk(root_dir):
+    for root, _dirs, files in os.walk(SRC_DIR):
@@
-    with open(r"c:\WSGTA\universal-or-strategy\scripts\trace_results.md", "w", encoding="utf-8") as out:
+    with (ROOT_DIR / "scripts" / "trace_results.md").open("w", encoding="utf-8") as out:

Also applies to: 48-48

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/zero_caller_trace.py` around lines 17 - 18, Replace hard-coded
Windows absolute paths by deriving the repo root from __file__ and building
paths with pathlib: compute root_dir = Path(__file__).resolve().parent.parent
(or the appropriate parent to reach the repository root), set src_dir = root_dir
/ "src" and use root_dir / "trace_results.md" when opening/writing the output;
update the other occurrence around line 48 the same way so all scan/write paths
are repository-relative and platform-independent.

Comment on lines +34 to +44
# Ignore the definition itself roughly
if "void " + cand in line or "Task " + cand in line or "bool " + cand in line:
continue
# Look for candidate without opening parenthesis after it (ignoring whitespace)
# or cases where it's used as an event handler: Object.Event += Candidate;
if cand in line:
match = re.search(r'\b' + cand + r'\b(?!\s*\()', line)
if match:
results[cand].append((os.path.basename(path), i+1, line.strip()))
elif "override" in line and cand in line:
results[cand].append((os.path.basename(path), i+1, line.strip() + " [OVERRIDE]"))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Strip comments and string literals before counting hits.

This matcher records // ... Candidate and Print("...Candidate...") as usages, so the generated report is dominated by comments and log strings instead of real delegate references. That makes the scan unsafe for caller analysis or dead-code decisions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/zero_caller_trace.py` around lines 34 - 44, The matcher is counting
occurrences inside comments and string literals; before testing each line for
candidates (the code that uses variables cand, match, results, path, line),
strip/ignore comments and string literals first (remove //... and /*...*/ spans
and quoted strings including escaped quotes and verbatim @"..." forms) or
operate on a preprocessed version of the file content, then run the existing
regex search r'\b' + cand + r'\b(?!\s*\()' and the override check; update the
logic around the match/results append so only matches from code (not comments or
string literals) are recorded.

Comment on lines +45 to +46
except Exception as e:
pass
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Do not silently ignore scan failures.

An unreadable file currently turns into a false "NO EVENT DELEGATE FOUND", which makes the report untrustworthy. At minimum, surface the failing path and error; ideally fail the run.

🧰 Tools
🪛 Ruff (0.15.5)

[error] 45-46: try-except-pass detected, consider logging the exception

(S110)


[warning] 45-45: Do not catch blind exception: Exception

(BLE001)


[error] 45-45: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/zero_caller_trace.py` around lines 45 - 46, The except Exception as
e: pass silently swallows scan failures; replace it so the failing file path and
exception are surfaced and the run fails: in scripts/zero_caller_trace.py locate
the except block (the except Exception as e handler) and either log the error
with full context (e.g., logging.exception or processLogger.error including the
file path variable) and then re-raise the exception or call sys.exit(1) to fail
the run; ensure the log message includes the path being scanned and the
exception message/traceback so the report is not misleading.

Comment on lines +486 to +489
try
{
acct.Submit(new[] { newEntry });
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Re-check the master fill state at actual submit time.

The earlier masterFilled guard runs before TriggerCustomEvent; the master can fill in that gap and Line 488 will still submit a follower replacement. Re-run that check here and route the account into REAPER repair instead of sending a new entry.

Based on learnings: "Before submitting replacement order, check if master already filled; if yes, route to REAPER repair instead".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/V12_002.Orders.Callbacks.Propagation.cs` around lines 486 - 489, Re-check
the master's filled state immediately before submitting instead of
unconditionally calling acct.Submit(new[] { newEntry });—evaluate the current
masterFilled condition (or call the same helper used earlier to determine master
fill) and if the master is now filled, route this account/entry into the REAPER
repair flow (invoke the project's REAPER repair handler) rather than calling
acct.Submit; only call acct.Submit(new[] { newEntry }) when the re-checked
masterFilled is false.

Comment on lines +62 to +63
// BUG-M2: Clear in-flight guard after successful submission
_reaperNakedStopInFlight.TryRemove(ExpKey(item.AccountName), out _); // [Build 969.3] - Clears guard for immediate retry if broker update latches
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Keep the naked-stop guard until the broker has acknowledged the order.

Line 63 clears _reaperNakedStopInFlight immediately after Submit. If the naked-position detector runs again before the working stop is observed, the same account can be queued twice and end up with duplicate emergency stops. Clear this from the order/update path, not from the happy-path submit.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/V12_002.REAPER.NakedStop.cs` around lines 62 - 63, The current code
clears the naked-stop guard immediately after Submit by calling
_reaperNakedStopInFlight.TryRemove(ExpKey(item.AccountName)), which allows the
naked-position detector to requeue the same account before the broker
acknowledges the stop; instead, remove the TryRemove call here and move
guard-clear logic into the order/update acknowledgement path (the code that
processes broker order confirmations/updates), ensuring _reaperNakedStopInFlight
is only cleared when a working stop or broker acknowledgment for the submitted
stop is observed; update references to ExpKey(item.AccountName) in that
acknowledgement handler so the guard is removed reliably and duplicates cannot
be enqueued.

Comment on lines +58 to +64
if (orphanCount >= 3)
{
Print(string.Format("[REAPER] SELF-HEAL: {0} has no PositionInfo after 3 attempts. Force-zeroing expectedPositions to unblock repair loop.",
accountName));
// SetExpectedPositionLocked(..., 0) already removes from _dispatchSyncPendingExpKeys internally.
SetExpectedPositionLocked(ExpKey(accountName), 0);
_reaperOrphanRepairCount.TryRemove(accountName, out _);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don't force expected positions to zero here.

If the follower is still live and PositionInfo is missing because of a partial cleanup race, Line 63 erases the expected side of the desync instead of reconciling it. Use a signed rollback/reconcile path based on the current expected value and actual account position, not blanket zeroing.

As per coding guidelines: "Use Signed Delta Rollbacks for expected position cleanup in ghost-order prevention; never use blanket zeroing".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/V12_002.REAPER.Repair.cs` around lines 58 - 64, The current code
force-zeroes expected positions via
SetExpectedPositionLocked(ExpKey(accountName), 0) which violates the
signed-delta rollback rule; instead, fetch the current expected value (e.g.,
GetExpectedPositionLocked(ExpKey(accountName)) or lookup
_expectedPositions[ExpKey(accountName)]), fetch the actual account
position/PositionInfo for accountName (e.g., GetAccountPosition(accountName) or
PositionInfo lookup), compute signedDelta = actualPosition - currentExpected,
and apply a signed rollback/reconcile (either by calling an existing
ApplySignedDelta/AdjustExpectedPosition method or by calling
SetExpectedPositionLocked(ExpKey(accountName), currentExpected + signedDelta))
only when signedDelta != 0; then remove the entry from _reaperOrphanRepairCount
as before. Ensure you do not blanket-zero expected positions and that the
reconcile uses the signed delta derived from currentExpected and actualPosition.

Comment on lines +174 to +179
repairPos.BracketSubmitted = false;
// B966: reaperThread -- Enqueue not applicable (would drain on wrong thread).
// ConcurrentDictionary single-write is inherently thread-safe.
entryOrders[repairEntryName] = repairEntry;

targetAcct.Submit(new[] { repairEntry });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Publish the repair order to strategy state only after submit succeeds.

repairPos.BracketSubmitted and entryOrders[repairEntryName] are updated before targetAcct.Submit. If Submit throws, the strategy now tracks a repair order the broker never accepted, which can block later repair attempts or break order matching. Move the state update after a successful submit and guard the repairPos mutation with lock(stateLock).

Suggested fix
-                repairPos.BracketSubmitted = false;
-                // B966: reaperThread -- Enqueue not applicable (would drain on wrong thread).
-                // ConcurrentDictionary single-write is inherently thread-safe.
-                entryOrders[repairEntryName] = repairEntry;
-
                 targetAcct.Submit(new[] { repairEntry });
+
+                lock (stateLock)
+                {
+                    repairPos.BracketSubmitted = false;
+                }
+                entryOrders[repairEntryName] = repairEntry;
As per coding guidelines: "All state mutations (activePositions, expectedPositions) MUST be guarded by lock(stateLock)".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/V12_002.REAPER.Repair.cs` around lines 174 - 179, The code sets
repairPos.BracketSubmitted = false and entryOrders[repairEntryName] =
repairEntry before calling targetAcct.Submit, which can leave strategy state
inconsistent if Submit throws; move the entryOrders[repairEntryName] =
repairEntry and the mutation of repairPos.BracketSubmitted so they occur only
after targetAcct.Submit completes successfully, and wrap the repairPos mutation
(and any other state mutations such as activePositions/expectedPositions or
entryOrders) inside lock(stateLock) to satisfy the "All state mutations ... MUST
be guarded by lock(stateLock)" guideline; keep targetAcct.Submit outside the
lock and ensure exceptions prevent the state update.

Comment thread src/V12_002.SIMA.cs
Comment on lines +85 to +89
{
Interlocked.Exchange(ref _lastExpectedPositionSetTicks, DateTime.UtcNow.Ticks);
if (newVal != 0)
StampAccountFillGrace(accountName);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify key format used in StampAccountFillGrace and its consumers
echo "=== StampAccountFillGrace definition ==="
rg -n -A5 'void StampAccountFillGrace' src/

echo ""
echo "=== All calls to StampAccountFillGrace ==="
rg -n -B2 -A2 'StampAccountFillGrace\(' src/

echo ""
echo "=== _accountFillGraceTicks usage ==="
rg -n '_accountFillGraceTicks' src/

Repository: mkalhitti-cloud/universal-or-strategy

Length of output: 1875


Fix key format mismatch: StampAccountFillGrace() calls pass raw accountName but method expects composite expKey.

Lines 88 and 114 call StampAccountFillGrace(accountName) with raw account name. The method signature (V12_002.REAPER.cs:53) expects expKey, and both storage and lookup in IsReaperFillGraceActive use the same expKey format. Raw accountName keys will not match the composite keys stored in _accountFillGraceTicks, breaking grace-window detection.

Pass the composite key format (e.g., ExpKey(accountName, instrument) or equivalent) to both calls instead of raw accountName.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/V12_002.SIMA.cs` around lines 85 - 89, Calls to StampAccountFillGrace are
passing raw accountName but the method and lookup use a composite expKey; update
both calls (the ones shown and the later call at line ~114) to construct and
pass the same composite key used by IsReaperFillGraceActive and the
_accountFillGraceTicks map (e.g., call ExpKey(accountName, instrument) or the
project's composite key helper) so the stored and queried keys match; ensure you
reference and use the same key-construction helper/function used elsewhere so
StampAccountFillGrace receives the correct expKey.

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

This PR targets Build 948’s “follower order loss during master chart-moves” incident by hardening the follower replace/cleanup interaction (Move-Grace suppression + expected qty repair), and by refactoring REAPER functionality into split partial modules while bumping the build tag.

Changes:

  • Suppresses follower cascade teardown during an in-flight Replace FSM and tightens cascade key matching to prevent substring collateral cleanup.
  • Re-asserts/adjusts expectedPositions during follower replacement submission to prevent REAPER critical-desync flattens after replace gaps.
  • Splits REAPER repair/naked-stop logic into dedicated partial files and updates build tagging/docs/scripts.

Reviewed changes

Copilot reviewed 16 out of 19 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
universal-or-strategy.sln Adds a VS solution for tooling (Linting project).
tmp_linecounts.txt Adds local analysis artifact (line count inventory).
src/V12_002.cs Build tag bumped to 972 for the incident fix set.
src/V12_002.SIMA.cs Stamps account fill-grace when expected qty becomes non-zero.
src/V12_002.REAPER.cs Removes large REAPER blocks (moved into split partial modules).
src/V12_002.REAPER.Repair.cs Adds REAPER repair engine module (extracted).
src/V12_002.REAPER.NakedStop.cs Adds REAPER naked-position emergency stop module (extracted).
src/V12_002.Orders.Callbacks.Propagation.cs Adds expected qty re-assert + replacement expected delta adjustments and submit error handling.
src/V12_002.Orders.Callbacks.AccountOrders.cs Adds replace-cancel cascade suppression + safer cascade matching + helper utilities.
src/V12_002.Constants.cs Updates displayed “Build” version string.
scripts/zero_caller_trace.py Adds a helper script to trace delegate/event wiring.
scripts/trace_results.txt Adds scan output (appears UTF-16/binary).
scripts/trace_results.md Adds scan output (markdown).
scripts/dead_code_scan.py Adds a dead private method scanner intended as a PR gate.
scripts/build974_findings.txt Adds scan output/findings artifact.
check_ascii.py Adds a small ASCII byte checker script.
GEMINI.md Updates project standards doc (extractor protocol + dead code scan requirement).

Comment on lines 473 to 477
Order newEntry = acct.CreateOrder(
Instrument, spec.EntryAction, spec.EntryOrderType, TimeInForce.Gtc,
qty, limitPx, stopPx,
"MGE_" + Guid.NewGuid().ToString("N").Substring(0, 8),
fleetSignalName, null);
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

acct.CreateOrder(...) is not null-guarded (and not wrapped for exceptions). In this codebase Account.CreateOrder() can return null, which will break the subsequent submit path and can leave expectedPositions deltas applied. Add a CreateOrder try/catch + null check and ensure any expectedPositions adjustments in this method are rolled back on CreateOrder/Submit failure.

Copilot uses AI. Check for mistakes.
Instrument, closeAction, OrderType.StopMarket,
TimeInForce.Gtc, item.Qty,
0, stopPrice, "", signalName, null);

Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

acct.CreateOrder(...) can return null for disconnected/invalid accounts, but the result is submitted without a null-guard. Add a null check (and consider a fallback such as emergency flatten / stronger logging) before attempting to submit this emergency stop.

Suggested change
if (emergencyStop == null)
{
// CreateOrder can return null for disconnected/invalid accounts; do not attempt to submit.
_reaperNakedStopInFlight.TryRemove(ExpKey(item.AccountName), out _);
Print(string.Format(
"[REAPER][EMERGENCY_STOP_FAIL] {0}: CreateOrder returned null (account disconnected/invalid?)",
item.AccountName));
continue;
}

Copilot uses AI. Check for mistakes.
Comment thread src/V12_002.Constants.cs
Comment on lines 11 to 13
public const string StrategyName = "V12_002";
public const string Version = "Build 936";
public const string Version = "Build 970";
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

Constants.Version was updated to "Build 970" while this PR increments BUILD_TAG to 972 and the PR description is for Build 972. Please align the version string with the actual build/tag to avoid confusing diagnostics and support logs.

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +19
src_dir = r"c:\WSGTA\universal-or-strategy\src"
root_dir = r"c:\WSGTA\universal-or-strategy"

Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

This script hardcodes absolute Windows paths (c:\WSGTA\...) for scanning/output, which makes it non-portable for other dev machines/CI and can write outside the repo. Prefer deriving paths from __file__ (repo-relative) and writing outputs under scripts/ using relative paths.

Copilot uses AI. Check for mistakes.
Comment thread scripts/trace_results.md
Comment on lines +1 to +3
--- EVENT / DELEGATE SCAN RESULTS ---
ExecuteRMAEntry:
-> V12_002.Entries.RMA.cs:2 | // Contains: ExecuteTrendSplitEntry, GetRmaAnchorPrice, ExecuteRMAEntry,
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

This file looks like generated scan output from zero_caller_trace.py rather than source/documentation consumed by the strategy. Consider removing it from version control (or moving it under docs with a clear purpose) to avoid committing transient analysis artifacts.

Copilot uses AI. Check for mistakes.
Comment thread GEMINI.md

**ALL file splits MUST use a Python extractor script. Manual copy-paste is BANNED for splits exceeding 50 lines.**

- **Script Location**: `scripts/<module>_split.py` in the repo root.
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

This PR splits REAPER code into new partial files (Repair/NakedStop), but I don't see a corresponding extractor script (e.g., scripts/reaper_split.py) checked in. Since this section mandates extractor scripts for >50-line splits, please add the script used for this split (or update the requirement) so the reorg is reproducible and auditable.

Suggested change
- **Script Location**: `scripts/<module>_split.py` in the repo root.
- **Script Location (New Splits)**: For all new >50-line splits, check in a Python extractor at `scripts/<module>_split.py` in the repo root (for REAPER, this MUST be `scripts/reaper_split.py`).
- **Legacy Exception (REAPER Repair/NakedStop)**: The original REAPER Repair/NakedStop split predates Build 970 and does not have a persisted `scripts/reaper_split.py`; its extraction plan is documented in the originating PR description instead. This is a one-time legacy exception -- all future REAPER refactors MUST add and version-control `scripts/reaper_split.py`.

Copilot uses AI. Check for mistakes.
Comment thread tmp_linecounts.txt
Comment on lines +1 to +52
V12_002.UI.Compliance.cs,668
V12_002.Entries.RMA.cs,618
V12_002.UI.Callbacks.cs,551
V12_002.Orders.Management.StopSync.cs,547
V12_002.UI.IPC.Commands.Fleet.cs,526
V12_002.Orders.Callbacks.Propagation.cs,515
V12_002.Entries.FFMA.cs,497
V12_002.Orders.Callbacks.cs,490
V12_002.Entries.Trend.cs,454
V12_002.Trailing.cs,451
V12_002.Orders.Management.Cleanup.cs,450
V12_002.Orders.Management.Flatten.cs,450
V12_002.SIMA.Execution.cs,448
V12_002.SIMA.Dispatch.cs,447
V12_002.Orders.Callbacks.Execution.cs,435
V12_002.Lifecycle.cs,410
V12_002.Properties.cs,408
SignalBroadcaster.cs,398
V12_002.Orders.Callbacks.AccountOrders.cs,386
V12_002.SIMA.Flatten.cs,386
V12_002.REAPER.Audit.cs,367
V12_002.SIMA.Lifecycle.cs,367
V12_002.Entries.Retest.cs,361
V12_002.PositionInfo.cs,360
V12_002.UI.IPC.Commands.Misc.cs,348
V12_002.UI.IPC.cs,344
V12_002.cs,344
V12_002.Trailing.StopUpdate.cs,343
V12_002.Trailing.Breakeven.cs,342
V12_002.Symmetry.Follower.cs,320
V12_002.LogicAudit.cs,319
V12_002.Symmetry.Replace.cs,301
V12_002.UI.IPC.Server.cs,290
V12_002.UI.Sizing.cs,285
V12_002.UI.IPC.Commands.Mode.cs,273
V12_002.UI.IPC.Commands.Config.cs,270
V12_002.Entries.OR.cs,263
V12_002.Orders.Management.cs,240
V12_002.BarUpdate.cs,236
V12_002.SIMA.cs,215
V12_002.DrawingHelpers.cs,210
V12_002.SIMA.Fleet.cs,208
V12_002.REAPER.Repair.cs,207
V12_002.Entries.MOMO.cs,202
V12_002.Symmetry.cs,200
V12_002.REAPER.cs,172
V12_002.REAPER.NakedStop.cs,79
V12_002.Atm.cs,18
V12_002.AccountUpdate.cs,17
V12_002.Entries.cs,17
V12_002.Constants.cs,15
V12_002.Data.cs,11
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

This looks like a temporary/local analysis artifact (line counts) rather than source or documentation. Please remove it from the PR (or add an ignore rule) to keep the repo clean per the hygiene standards.

Suggested change
V12_002.UI.Compliance.cs,668
V12_002.Entries.RMA.cs,618
V12_002.UI.Callbacks.cs,551
V12_002.Orders.Management.StopSync.cs,547
V12_002.UI.IPC.Commands.Fleet.cs,526
V12_002.Orders.Callbacks.Propagation.cs,515
V12_002.Entries.FFMA.cs,497
V12_002.Orders.Callbacks.cs,490
V12_002.Entries.Trend.cs,454
V12_002.Trailing.cs,451
V12_002.Orders.Management.Cleanup.cs,450
V12_002.Orders.Management.Flatten.cs,450
V12_002.SIMA.Execution.cs,448
V12_002.SIMA.Dispatch.cs,447
V12_002.Orders.Callbacks.Execution.cs,435
V12_002.Lifecycle.cs,410
V12_002.Properties.cs,408
SignalBroadcaster.cs,398
V12_002.Orders.Callbacks.AccountOrders.cs,386
V12_002.SIMA.Flatten.cs,386
V12_002.REAPER.Audit.cs,367
V12_002.SIMA.Lifecycle.cs,367
V12_002.Entries.Retest.cs,361
V12_002.PositionInfo.cs,360
V12_002.UI.IPC.Commands.Misc.cs,348
V12_002.UI.IPC.cs,344
V12_002.cs,344
V12_002.Trailing.StopUpdate.cs,343
V12_002.Trailing.Breakeven.cs,342
V12_002.Symmetry.Follower.cs,320
V12_002.LogicAudit.cs,319
V12_002.Symmetry.Replace.cs,301
V12_002.UI.IPC.Server.cs,290
V12_002.UI.Sizing.cs,285
V12_002.UI.IPC.Commands.Mode.cs,273
V12_002.UI.IPC.Commands.Config.cs,270
V12_002.Entries.OR.cs,263
V12_002.Orders.Management.cs,240
V12_002.BarUpdate.cs,236
V12_002.SIMA.cs,215
V12_002.DrawingHelpers.cs,210
V12_002.SIMA.Fleet.cs,208
V12_002.REAPER.Repair.cs,207
V12_002.Entries.MOMO.cs,202
V12_002.Symmetry.cs,200
V12_002.REAPER.cs,172
V12_002.REAPER.NakedStop.cs,79
V12_002.Atm.cs,18
V12_002.AccountUpdate.cs,17
V12_002.Entries.cs,17
V12_002.Constants.cs,15
V12_002.Data.cs,11

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +26
=== BUILD 974 ANTIGRAVITY SCAN RESULTS ===
Total private methods scanned: 230
Zero external callers: 10
Single external caller: 108

--- ZERO CALLERS (highest priority) ---
METHOD=ExecuteRMAEntry FILE=V12_002.Entries.RMA.cs LINE=185
METHOD=ExecuteRMAEntryCustom FILE=V12_002.Entries.RMA.cs LINE=356
METHOD=HandleExternalSignal FILE=V12_002.UI.IPC.cs LINE=220
METHOD=ListenForRemote FILE=V12_002.UI.IPC.Server.cs LINE=65
METHOD=OnAccountExecutionUpdate FILE=V12_002.UI.Compliance.cs LINE=273
METHOD=OnAccountOrderUpdate FILE=V12_002.Orders.Callbacks.AccountOrders.cs LINE=37
METHOD=OnBreakevenButtonClick FILE=V12_002.Trailing.Breakeven.cs LINE=35
METHOD=OnChartClick FILE=V12_002.UI.Callbacks.cs LINE=76
METHOD=OnKeyDown FILE=V12_002.UI.Callbacks.cs LINE=172
METHOD=ReaperLoop FILE=V12_002.REAPER.cs LINE=122

--- SINGLE CALLER (needs verification) ---
METHOD=ActivateMOMOMode FILE=V12_002.Entries.MOMO.cs LINE=184 CALLER=V12_002.UI.IPC.Commands.Mode.cs:L106
METHOD=AddOrUpdateExpectedPositionLocked FILE=V12_002.SIMA.cs LINE=89 CALLER=V12_002.SIMA.Lifecycle.cs:L170
METHOD=AppendDailySummary FILE=V12_002.UI.Compliance.cs LINE=133 CALLER=V12_002.UI.Compliance.cs:L170
METHOD=ApplySimaState FILE=V12_002.SIMA.Lifecycle.cs LINE=44 CALLER=V12_002.UI.IPC.Commands.Misc.cs:L91
METHOD=AttachChartClickHandler FILE=V12_002.UI.Callbacks.cs LINE=55 CALLER=V12_002.Lifecycle.cs:L300
METHOD=AttachHotkeys FILE=V12_002.UI.Callbacks.cs LINE=39 CALLER=V12_002.Lifecycle.cs:L299
METHOD=AuditMasterAccountIfNeeded FILE=V12_002.REAPER.Audit.cs LINE=221 CALLER=V12_002.REAPER.Audit.cs:L36
METHOD=AuditSingleFleetAccount FILE=V12_002.REAPER.Audit.cs LINE=51 CALLER=V12_002.REAPER.Audit.cs:L27
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

This appears to be generated scan output ("BUILD 974 ...") and not required at runtime. Please remove it from the PR (or move it to documented, intentionally tracked docs) to avoid committing analysis artifacts and build-number confusion.

Suggested change
=== BUILD 974 ANTIGRAVITY SCAN RESULTS ===
Total private methods scanned: 230
Zero external callers: 10
Single external caller: 108
--- ZERO CALLERS (highest priority) ---
METHOD=ExecuteRMAEntry FILE=V12_002.Entries.RMA.cs LINE=185
METHOD=ExecuteRMAEntryCustom FILE=V12_002.Entries.RMA.cs LINE=356
METHOD=HandleExternalSignal FILE=V12_002.UI.IPC.cs LINE=220
METHOD=ListenForRemote FILE=V12_002.UI.IPC.Server.cs LINE=65
METHOD=OnAccountExecutionUpdate FILE=V12_002.UI.Compliance.cs LINE=273
METHOD=OnAccountOrderUpdate FILE=V12_002.Orders.Callbacks.AccountOrders.cs LINE=37
METHOD=OnBreakevenButtonClick FILE=V12_002.Trailing.Breakeven.cs LINE=35
METHOD=OnChartClick FILE=V12_002.UI.Callbacks.cs LINE=76
METHOD=OnKeyDown FILE=V12_002.UI.Callbacks.cs LINE=172
METHOD=ReaperLoop FILE=V12_002.REAPER.cs LINE=122
--- SINGLE CALLER (needs verification) ---
METHOD=ActivateMOMOMode FILE=V12_002.Entries.MOMO.cs LINE=184 CALLER=V12_002.UI.IPC.Commands.Mode.cs:L106
METHOD=AddOrUpdateExpectedPositionLocked FILE=V12_002.SIMA.cs LINE=89 CALLER=V12_002.SIMA.Lifecycle.cs:L170
METHOD=AppendDailySummary FILE=V12_002.UI.Compliance.cs LINE=133 CALLER=V12_002.UI.Compliance.cs:L170
METHOD=ApplySimaState FILE=V12_002.SIMA.Lifecycle.cs LINE=44 CALLER=V12_002.UI.IPC.Commands.Misc.cs:L91
METHOD=AttachChartClickHandler FILE=V12_002.UI.Callbacks.cs LINE=55 CALLER=V12_002.Lifecycle.cs:L300
METHOD=AttachHotkeys FILE=V12_002.UI.Callbacks.cs LINE=39 CALLER=V12_002.Lifecycle.cs:L299
METHOD=AuditMasterAccountIfNeeded FILE=V12_002.REAPER.Audit.cs LINE=221 CALLER=V12_002.REAPER.Audit.cs:L36
METHOD=AuditSingleFleetAccount FILE=V12_002.REAPER.Audit.cs LINE=51 CALLER=V12_002.REAPER.Audit.cs:L27
This file previously contained transient BUILD 974 scan output and method listings.
To avoid committing generated analysis artifacts and build-specific data, the scan
results have been removed from source control. If you need current findings, run
the appropriate analysis tool locally instead of relying on checked-in output.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown

🤖 Antigravity Auto-Auditor (Gemini 2.5 Pro via Vertex AI)

Greetings. I am the Gemini CLI (Antigravity Auto-Auditor). I have analyzed this pull request against the GEMINI.md project standards. My findings are detailed below.

AUDIT RESULT: CHANGES REQUESTED

This pull request contains critical logic improvements and protocol enhancements. However, it fails the audit due to several violations of project standards. The PR cannot be merged until the following issues are addressed.


VIOLATIONS (BLOCKING)

  1. Repo Hygiene - Binary Guard VIOLATION

    • Standard: GEMINI.md, Section 4: "DO NOT commit .exe, .log, or .bak files. Use stashing or .gitignore."
    • Violation: The PR commits multiple binary or binary-like generated artifacts. These files should be added to .gitignore and removed from the commit history.
      • binary_check.txt
      • pr_comments.json
      • scripts/trace_results.txt
  2. Code Consistency VIOLATION

    • Standard: Implied by general good practice and the need for coherent versioning.
    • Violation: The build version is inconsistent across files, which will cause confusion and errors in deployment diagnostics.
      • File: src/V12_002.cs, Line 41: public const string BUILD_TAG = "973";
      • File: src/V12_002.Constants.cs, Line 11: public const string Version = "Build 970";
    • Action: Unify the build number across all relevant constants.

CODE LOGIC & STANDARDS COMPLIANCE (Non-Blocking)

The core C# logic changes in this PR are of high quality and adhere to project standards.

  • (PASS) FSM / MOVE-SYNC Pattern: The changes in V12_002.Orders.Callbacks.AccountOrders.cs and V12_002.Orders.Callbacks.Propagation.cs are exemplary. The "Meta-Purge Fix" and the FSM-aware guards preventing cascade teardowns during a master replace are critical improvements. They directly address a race condition and strengthen the MOVE-SYNC protocol as required. The defensive re-assertion of expectedPositions before replacement submission is a robust solution.

  • (PASS) Concurrency: All observed mutations to expectedPositions (e.g., AddExpectedPositionDeltaLocked) appear to correctly use the Locked method convention, implying they are guarded by stateLock, which is compliant with the standard.

  • (PASS) Refactoring: The refactoring of the V12_002.REAPER.cs module into V12_002.REAPER.Repair.cs and V12_002.REAPER.NakedStop.cs is a significant step towards improving "Metabolic Elegance." This PR introduces the Python Extractor Protocol, and this refactoring appears to be the first application of it. This is a positive architectural change.

  • (NOTE) Repo Hygiene: The PR introduces several report-like text files (scripts/build974_findings.txt, scripts/trace_results.md). While not a strict violation of the .log rule, committing transient analysis reports is poor practice. These findings are better suited for the PR description. They should be removed from the final commit.


SUMMARY

This PR contains essential bug fixes for the order management FSM. The logical changes are approved. However, the PR is blocked by violations of repository hygiene and versioning consistency.

Required actions before merge:

  1. Remove all binary/generated files from the commit.
  2. Update .gitignore to prevent future commits of these file types.
  3. Correct the inconsistent build numbers in V12_002.cs and V12_002.Constants.cs.
  4. (Recommended) Remove the transient scan reports (.txt, .md) from the scripts/ directory.

Resubmit after resolving these issues. The audit will be re-initiated.

@github-actions
Copy link
Copy Markdown

────────────────────────────────────────────────────────────────────────────────
Update git name with: git config user.name "Your Name"
Update git email with: git config user.email "you@example.com"
You can skip this check with --no-gitignore
Added .aider* to .gitignore
Aider v0.86.2
Main model: gpt-4o with diff edit format
Weak model: gpt-4o-mini
Git repo: .git with 308 files
Repo-map: using 4096 tokens, auto refresh

https://aider.chat/HISTORY.html#release-notes

Initial repo scan can be slow in larger repos, but only happens once.
Repo-map can't include
/home/runner/work/universal-or-strategy/universal-or-strategy/.claude/worktrees/
affectionate-franklin
Has it been deleted from the file system but not from git?
Repo-map can't include
/home/runner/work/universal-or-strategy/universal-or-strategy/.claude/worktrees/
sleepy-jepsen
Has it been deleted from the file system but not from git?
Repo-map can't include
/home/runner/work/universal-or-strategy/universal-or-strategy/AntigravityMobile
Has it been deleted from the file system but not from git?
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 0.2 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 0.5 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 1.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 2.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 4.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 8.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 16.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 32.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.

https://platform.openai.com/docs/guides/error-codes/api-errors

Copy link
Copy Markdown

@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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/V12_002.Orders.Callbacks.AccountOrders.cs (1)

264-283: ⚠️ Potential issue | 🔴 Critical

Add master fill re-check inside SubmitFollowerReplacement before submitting the replacement order.

The master fill check at line ~240 in AccountOrders.cs correctly guards against replacement when the master is already filled. However, this check occurs before TriggerCustomEvent queues the callback. If the master fills during the gap between the check and callback execution, SubmitFollowerReplacement will submit the replacement despite the master now being live.

Before calling acct.Submit(new[] { newEntry }) at line 488, re-verify using spec.MasterSignalName that the master has not filled. If it has, route to REAPER repair instead, consistent with the earlier guard logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/V12_002.Orders.Callbacks.AccountOrders.cs` around lines 264 - 283, The
callback path can race: re-check the master fill status inside
SubmitFollowerReplacement just before submitting the replacement so you don't
submit after the master filled; specifically, right before the acct.Submit(new[]
{ newEntry }) call in SubmitFollowerReplacement, query the master by
spec.MasterSignalName (same check performed earlier at ~line 240) and if the
master is now filled, do not call acct.Submit but instead route the flow to the
REAPER repair path (same logic/handling used by the earlier guard), and ensure
any reservation/state cleanup mirrors that REAPER branch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/audits/LIVE_FREEZE_FORENSIC_BRIEF_2026_03_09.md`:
- Around line 148-152: The "Direct Evidence" heading names processes
(`@testsprite/testsprite-mcp`, mcp.supermemory.ai) and source files
(%USERPROFILE%\.gemini\antigravity\mcp_config.json,
%USERPROFILE%\.cursor\mcp.json) but lacks the actual captured process snapshot;
either add a citation to the specific artifact/report that demonstrates the
running processes (e.g., a trace_*.txt or process_snapshot_*.log with timestamp
and hash) and reference it inline under Direct Evidence, or change the heading
to "Observation" or "Inference" and adjust the wording to reflect that no
snapshot was captured; update the text around the process names and source files
accordingly.
- Around line 146-158: The "3. Tertiary: Ghost MCP Process Saturation
(Discovered 2026-03-11)" block is appended to a brief scoped as "Build: 960" and
references "B973+", which confuses timeline and scope; move this entire block
(title, Direct Evidence, Inference, Mitigation) into a new dated addendum
section labeled e.g., "Addendum (Discovered 2026-03-11)" or update the brief
header/build metadata to include the later discovery date and remediation tag
"B973+" so the chronology is explicit; ensure references to file artifacts
(`%USERPROFILE%\.gemini\antigravity\mcp_config.json`,
`%USERPROFILE%\.cursor\mcp.json`, and `~/.claude/settings.json`) and the
original section title remain unchanged within the moved or updated content.

In `@INFRASTRUCTURE_PROTOCOL.md`:
- Line 7: The header "## 9. MCP Environment Hygiene (Ghost Process Prevention)"
breaks monotonic numbering; fix by either moving this section to its correct
position after the existing numbered sections or renumbering this and all
subsequent headers to follow the sequence (e.g., change "## 9 ..." to the next
number in order and adjust downstream headings accordingly) so the document
headings remain monotonic and easy to reference.
- Around line 13-15: Update the "Ghost Scan" step to use Get-CimInstance
Win32_Process instead of Get-Process so CommandLine is reliably available across
PowerShell versions; replace the current command reference (Get-Process node |
Select-Object Id, Path, CommandLine) with a Get-CimInstance-based query (using
Win32_Process and selecting ProcessId, ExecutablePath, CommandLine) in the Ghost
Scan instructions so the procedure can detect and safely terminate testsprite or
supermemory processes even under PowerShell 5.1 or when process protections
would hide CommandLine.

In `@src/V12_002.Orders.Callbacks.AccountOrders.cs`:
- Around line 115-133: TryFindMasterEntryForOrder currently only checks the live
entryOrders slot and can miss master-replace cascade cancels when
OnAccountOrderUpdate runs later; update the method so that inside the loop, if
entryOrders.TryGetValue(kvp.Key, out trackedEntry) fails to match
OrdersMatchByRefOrId(trackedEntry, order), also call
IsMasterReplaceCascadeCancellation(kvp.Key, order) and, if it returns true, set
masterEntryName = kvp.Key and return true; this ensures master-replace cancels
are detected even if entryOrders has already been swapped to the new master
order.
- Around line 463-479: The code reads expectedPositions and conditionally calls
DeltaExpectedPositionLocked without holding stateLock, causing a non-atomic
check-and-mutate; wrap the whole branch that reads expectedPositions, checks
currentExp, calls DeltaExpectedPositionLocked and ClearDispatchSyncPending
inside a lock(stateLock) (i.e., acquire stateLock before calling ExpKey/calling
expectedPositions.TryGetValue, perform the currentExp==0 check and either
suppress or call DeltaExpectedPositionLocked while still holding stateLock) so
the signed rollback and purge-race guard are atomic; leave the RemoveDrawObject
call outside the lock if it is non-state-mutating, otherwise include it under
the same lock.

---

Outside diff comments:
In `@src/V12_002.Orders.Callbacks.AccountOrders.cs`:
- Around line 264-283: The callback path can race: re-check the master fill
status inside SubmitFollowerReplacement just before submitting the replacement
so you don't submit after the master filled; specifically, right before the
acct.Submit(new[] { newEntry }) call in SubmitFollowerReplacement, query the
master by spec.MasterSignalName (same check performed earlier at ~line 240) and
if the master is now filled, do not call acct.Submit but instead route the flow
to the REAPER repair path (same logic/handling used by the earlier guard), and
ensure any reservation/state cleanup mirrors that REAPER branch.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 620455f9-9d0e-4ac3-859e-abf28d886427

📥 Commits

Reviewing files that changed from the base of the PR and between 6ac938d and c9d5ec0.

📒 Files selected for processing (4)
  • INFRASTRUCTURE_PROTOCOL.md
  • docs/audits/LIVE_FREEZE_FORENSIC_BRIEF_2026_03_09.md
  • src/V12_002.Orders.Callbacks.AccountOrders.cs
  • src/V12_002.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/V12_002.cs

Comment on lines +146 to +158
## 3. Tertiary: Ghost MCP Process Saturation (Discovered 2026-03-11)

**Direct Evidence:** During the March 11 stabilization mission, multiple "Ghost" Node.js processes were discovered spawning autonomously.
- Processes: `@testsprite/testsprite-mcp` and `mcp.supermemory.ai`.
- Source A: `%USERPROFILE%\.gemini\antigravity\mcp_config.json`
- Source B: `%USERPROFILE%\.cursor\mcp.json`

**Inference:** These processes consume platform resources and create asynchronous "silent freezes" in the agent environments (Claude/Antigravity), potentially leading to stalled execution cycles during high-velocity trading windows.

**Mitigation (B973+):**
- Deleted all `mcp_config.json` and `mcp.json` files outside of the primary `~/.claude/settings.json`.
- Pruned `~/.claude/settings.json` to only allow `csharp-lsp` and `github` plugins.
- Added a "Zero-Ghost" requirement to session-start protocols.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Separate this into an addendum or re-baseline the brief metadata.

This section is explicitly “Discovered 2026-03-11” and references B973+, but it is appended after the conclusion of a brief still scoped as Build: 960. That blurs whether this is part of the original incident analysis or later remediation context. Moving it into a dated addendum, or updating the brief header/build scope, would keep the forensic timeline clean.

🧰 Tools
🪛 LanguageTool

[style] ~156-~156: This phrase is redundant. Consider using “outside”.
Context: ... mcp_config.json and mcp.json files outside of the primary ~/.claude/settings.json. ...

(OUTSIDE_OF)


[uncategorized] ~157-~157: The official name of this software platform is spelled with a capital “H”.
Context: ...gs.jsonto only allowcsharp-lspandgithub` plugins. - Added a "Zero-Ghost" requir...

(GITHUB)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/audits/LIVE_FREEZE_FORENSIC_BRIEF_2026_03_09.md` around lines 146 - 158,
The "3. Tertiary: Ghost MCP Process Saturation (Discovered 2026-03-11)" block is
appended to a brief scoped as "Build: 960" and references "B973+", which
confuses timeline and scope; move this entire block (title, Direct Evidence,
Inference, Mitigation) into a new dated addendum section labeled e.g., "Addendum
(Discovered 2026-03-11)" or update the brief header/build metadata to include
the later discovery date and remediation tag "B973+" so the chronology is
explicit; ensure references to file artifacts
(`%USERPROFILE%\.gemini\antigravity\mcp_config.json`,
`%USERPROFILE%\.cursor\mcp.json`, and `~/.claude/settings.json`) and the
original section title remain unchanged within the moved or updated content.

Comment on lines +148 to +152
**Direct Evidence:** During the March 11 stabilization mission, multiple "Ghost" Node.js processes were discovered spawning autonomously.
- Processes: `@testsprite/testsprite-mcp` and `mcp.supermemory.ai`.
- Source A: `%USERPROFILE%\.gemini\antigravity\mcp_config.json`
- Source B: `%USERPROFILE%\.cursor\mcp.json`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Cite the actual process snapshot before calling this “Direct Evidence.”

The new section names the processes and their source files, but it does not point to a captured artifact analogous to the earlier trace_*.txt evidence. In a forensic brief, this should either cite the exact process snapshot/report that proved the finding or be labeled as an observation/inference instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/audits/LIVE_FREEZE_FORENSIC_BRIEF_2026_03_09.md` around lines 148 - 152,
The "Direct Evidence" heading names processes (`@testsprite/testsprite-mcp`,
mcp.supermemory.ai) and source files
(%USERPROFILE%\.gemini\antigravity\mcp_config.json,
%USERPROFILE%\.cursor\mcp.json) but lacks the actual captured process snapshot;
either add a citation to the specific artifact/report that demonstrates the
running processes (e.g., a trace_*.txt or process_snapshot_*.log with timestamp
and hash) and reference it inline under Direct Evidence, or change the heading
to "Observation" or "Inference" and adjust the wording to reflect that no
snapshot was captured; update the text around the process names and source files
accordingly.


---

## 9. MCP Environment Hygiene (Ghost Process Prevention)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Keep the section numbering monotonic.

Placing ## 9 before ## 1 makes the protocol hard to reference and follow. Either move this section after the existing numbered sections or renumber the document from here downward.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@INFRASTRUCTURE_PROTOCOL.md` at line 7, The header "## 9. MCP Environment
Hygiene (Ghost Process Prevention)" breaks monotonic numbering; fix by either
moving this section to its correct position after the existing numbered sections
or renumbering this and all subsequent headers to follow the sequence (e.g.,
change "## 9 ..." to the next number in order and adjust downstream headings
accordingly) so the document headings remain monotonic and easy to reference.

Comment on lines +13 to +15
3. **Ghost Scan:** If the agent environment feels sluggish, run:
`Get-Process node | Select-Object Id, Path, CommandLine`
Immediately terminate any `testsprite` or `supermemory` processes.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Does PowerShell Get-Process node | Select-Object Id, Path, CommandLinereliably exposeCommandLine in Windows PowerShell 5.1 and PowerShell 7? What is the recommended command to enumerate Node.js processes with full command lines?

💡 Result:

  • Windows PowerShell 5.1: Get-Process returns System.Diagnostics.Process objects without a CommandLine property, so Get-Process node | Select-Object ... CommandLine won’t reliably work (it’ll be missing / always $null). (stackoverflow.com)
  • PowerShell 7 (Windows): Get-Process does expose a CommandLine property, but it’s not guaranteed for every process: if PowerShell can’t query a given process (often permissions / protected processes), CommandLine may be $null (running elevated helps but still won’t get everything). (stackoverflow.com)

Recommended way to enumerate Node.js processes with full command lines (works in both 5.1 and 7)

Use CIM/WMI Win32_Process (it natively has CommandLine):

Get-CimInstance Win32_Process -Filter "Name='node.exe'" |
  Select-Object ProcessId, ExecutablePath, CommandLine |
  Format-List

Microsoft’s own guidance for getting command lines is Get-CimInstance win32_process | select commandline. (devblogs.microsoft.com)
Microsoft also documents Win32_Process as the Windows alternative when Get-Process doesn’t expose needed fields. (learn.microsoft.com)

Citations:


Replace Get-Process with Get-CimInstance to reliably query command lines.

Get-Process node | Select-Object Id, Path, CommandLine is unreliable: Windows PowerShell 5.1 does not expose CommandLine at all, and PowerShell 7 may return $null when permissions block access or processes are protected. The ghost-scan procedure cannot safely triage processes without this data.

Use Get-CimInstance Win32_Process, which natively exposes CommandLine across all PowerShell versions.

Suggested doc fix
-   `Get-Process node | Select-Object Id, Path, CommandLine`
-   Immediately terminate any `testsprite` or `supermemory` processes.
+   `Get-CimInstance Win32_Process -Filter "name = 'node.exe'" | Select-Object ProcessId, ExecutablePath, CommandLine`
+   Terminate only processes whose `CommandLine` positively matches `testsprite` or `supermemory`.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
3. **Ghost Scan:** If the agent environment feels sluggish, run:
`Get-Process node | Select-Object Id, Path, CommandLine`
Immediately terminate any `testsprite` or `supermemory` processes.
3. **Ghost Scan:** If the agent environment feels sluggish, run:
`Get-CimInstance Win32_Process -Filter "name = 'node.exe'" | Select-Object ProcessId, ExecutablePath, CommandLine`
Terminate only processes whose `CommandLine` positively matches `testsprite` or `supermemory`.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@INFRASTRUCTURE_PROTOCOL.md` around lines 13 - 15, Update the "Ghost Scan"
step to use Get-CimInstance Win32_Process instead of Get-Process so CommandLine
is reliably available across PowerShell versions; replace the current command
reference (Get-Process node | Select-Object Id, Path, CommandLine) with a
Get-CimInstance-based query (using Win32_Process and selecting ProcessId,
ExecutablePath, CommandLine) in the Ghost Scan instructions so the procedure can
detect and safely terminate testsprite or supermemory processes even under
PowerShell 5.1 or when process protections would hide CommandLine.

Comment on lines +115 to +133
private bool TryFindMasterEntryForOrder(Order order, KeyValuePair<string, PositionInfo>[] snapshot, out string masterEntryName)
{
masterEntryName = null;
if (order == null || snapshot == null) return false;

foreach (var kvp in snapshot)
{
PositionInfo pos = kvp.Value;
if (pos == null || pos.IsFollower) continue;

Order trackedEntry;
if (entryOrders.TryGetValue(kvp.Key, out trackedEntry) && OrdersMatchByRefOrId(trackedEntry, order))
{
masterEntryName = kvp.Key;
return true;
}
}

return false;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Do not resolve master-replace cancels from the live entryOrders slot alone.

OnAccountOrderUpdate is queued for later processing, so this helper can run after the master replacement has already swapped entryOrders[kvp.Key] to the new order. When that happens the cancelled old order no longer matches here, IsMasterReplaceCascadeCancellation returns false, and the code falls back into follower teardown again.

Possible fix
         Order trackedEntry;
         if (entryOrders.TryGetValue(kvp.Key, out trackedEntry) && OrdersMatchByRefOrId(trackedEntry, order))
         {
             masterEntryName = kvp.Key;
             return true;
         }
+
+        // The live slot may already point at the replacement order by the time the
+        // cancel event is drained from _accountOrderQueue.
+        if (string.Equals(kvp.Key, order.Name, StringComparison.Ordinal))
+        {
+            masterEntryName = kvp.Key;
+            return true;
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private bool TryFindMasterEntryForOrder(Order order, KeyValuePair<string, PositionInfo>[] snapshot, out string masterEntryName)
{
masterEntryName = null;
if (order == null || snapshot == null) return false;
foreach (var kvp in snapshot)
{
PositionInfo pos = kvp.Value;
if (pos == null || pos.IsFollower) continue;
Order trackedEntry;
if (entryOrders.TryGetValue(kvp.Key, out trackedEntry) && OrdersMatchByRefOrId(trackedEntry, order))
{
masterEntryName = kvp.Key;
return true;
}
}
return false;
private bool TryFindMasterEntryForOrder(Order order, KeyValuePair<string, PositionInfo>[] snapshot, out string masterEntryName)
{
masterEntryName = null;
if (order == null || snapshot == null) return false;
foreach (var kvp in snapshot)
{
PositionInfo pos = kvp.Value;
if (pos == null || pos.IsFollower) continue;
Order trackedEntry;
if (entryOrders.TryGetValue(kvp.Key, out trackedEntry) && OrdersMatchByRefOrId(trackedEntry, order))
{
masterEntryName = kvp.Key;
return true;
}
// The live slot may already point at the replacement order by the time the
// cancel event is drained from _accountOrderQueue.
if (string.Equals(kvp.Key, order.Name, StringComparison.Ordinal))
{
masterEntryName = kvp.Key;
return true;
}
}
return false;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/V12_002.Orders.Callbacks.AccountOrders.cs` around lines 115 - 133,
TryFindMasterEntryForOrder currently only checks the live entryOrders slot and
can miss master-replace cascade cancels when OnAccountOrderUpdate runs later;
update the method so that inside the loop, if entryOrders.TryGetValue(kvp.Key,
out trackedEntry) fails to match OrdersMatchByRefOrId(trackedEntry, order), also
call IsMasterReplaceCascadeCancellation(kvp.Key, order) and, if it returns true,
set masterEntryName = kvp.Key and return true; this ensures master-replace
cancels are detected even if entryOrders has already been swapped to the new
master order.

Comment on lines +463 to +479
if (cascadePos.ExecutingAccount != null)
{
int rollbackDelta = (cascadePos.Direction == MarketPosition.Long) ? -cascadePos.TotalContracts : cascadePos.TotalContracts;
int currentExp = 0;
expectedPositions.TryGetValue(ExpKey(cascadeAcctName), out currentExp);
if (currentExp == 0)
{
int rollbackDelta = (cascadePos.Direction == MarketPosition.Long) ? -cascadePos.TotalContracts : cascadePos.TotalContracts;
int currentExp = 0;
expectedPositions.TryGetValue(ExpKey(cascadeAcctName), out currentExp);
if (currentExp == 0)
{
Print(string.Format("[GHOST_FIX] SKIP cascade delta for {0}: expectedPositions already 0 (purge-race guard). Delta suppressed.",
cascadeAcctName));
}
else
{
DeltaExpectedPositionLocked(ExpKey(cascadeAcctName), rollbackDelta);
}
ClearDispatchSyncPending(ExpKey(cascadeAcctName));
try { RemoveDrawObject("SIMA_DESYNC_" + cascadeAcctName); } catch { }
Print(string.Format("[GHOST_FIX] SKIP cascade delta for {0}: expectedPositions already 0 (purge-race guard). Delta suppressed.",
cascadeAcctName));
}
}
else
{
Print(string.Format("[DEAD-01] CASCADE-FILLED: Master cancel {0} -- follower {1} on {2} is FILLED. Issuing emergency flatten.",
orderSignal, kvp.Key, cascadeAcctName));
if (cascadePos.ExecutingAccount != null)
else
{
Account filledFollowerAcct = cascadePos.ExecutingAccount;
TriggerCustomEvent(o => EmergencyFlattenSingleFleetAccount(filledFollowerAcct), null);
DeltaExpectedPositionLocked(ExpKey(cascadeAcctName), rollbackDelta);
}
ClearDispatchSyncPending(ExpKey(cascadeAcctName));
try { RemoveDrawObject("SIMA_DESYNC_" + cascadeAcctName); } catch { }
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Take the new expected-position rollback under stateLock.

This path reads expectedPositions, branches on currentExp == 0, and then mutates the same map via DeltaExpectedPositionLocked without the required lock. That makes the purge-race guard and signed rollback non-atomic with the other SIMA updates.

Possible fix
-                            int currentExp = 0;
-                            expectedPositions.TryGetValue(ExpKey(cascadeAcctName), out currentExp);
-                            if (currentExp == 0)
+                            string expectedKey = ExpKey(cascadeAcctName);
+                            bool skipRollback;
+                            lock (stateLock)
                             {
-                                Print(string.Format("[GHOST_FIX] SKIP cascade delta for {0}: expectedPositions already 0 (purge-race guard). Delta suppressed.",
-                                    cascadeAcctName));
-                            }
-                            else
-                            {
-                                DeltaExpectedPositionLocked(ExpKey(cascadeAcctName), rollbackDelta);
+                                int currentExp = 0;
+                                expectedPositions.TryGetValue(expectedKey, out currentExp);
+                                skipRollback = currentExp == 0;
+                                if (!skipRollback)
+                                    DeltaExpectedPositionLocked(expectedKey, rollbackDelta);
                             }
-                            ClearDispatchSyncPending(ExpKey(cascadeAcctName));
+                            if (skipRollback)
+                                Print(string.Format("[GHOST_FIX] SKIP cascade delta for {0}: expectedPositions already 0 (purge-race guard). Delta suppressed.",
+                                    cascadeAcctName));
+                            ClearDispatchSyncPending(expectedKey);
As per coding guidelines: "All state mutations (activePositions, expectedPositions) MUST be guarded by lock(stateLock)" and "Use Signed Delta Rollbacks for expected position cleanup in ghost-order prevention; never use blanket zeroing".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/V12_002.Orders.Callbacks.AccountOrders.cs` around lines 463 - 479, The
code reads expectedPositions and conditionally calls DeltaExpectedPositionLocked
without holding stateLock, causing a non-atomic check-and-mutate; wrap the whole
branch that reads expectedPositions, checks currentExp, calls
DeltaExpectedPositionLocked and ClearDispatchSyncPending inside a
lock(stateLock) (i.e., acquire stateLock before calling ExpKey/calling
expectedPositions.TryGetValue, perform the currentExp==0 check and either
suppress or call DeltaExpectedPositionLocked while still holding stateLock) so
the signed rollback and purge-race guard are atomic; leave the RemoveDrawObject
call outside the lock if it is non-state-mutating, otherwise include it under
the same lock.

@github-actions
Copy link
Copy Markdown

🤖 Antigravity Automated Auditor (Gemini 3.1 Pro via Vertex AI)

⚠️ Vertex AI Audit Failed to Execute: [VertexAI.ClientError]: got status: 404 Not Found. {"error":{"code":404,"message":"Publisher Model projects/project-263b6139-6893-4788-995/locations/us-east4/publishers/google/models/gemini-1.5-pro-002 was not found or your project does not have access to it. Please ensure you are using a valid model version. For more information, see: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versions","status":"NOT_FOUND"}}

@github-actions
Copy link
Copy Markdown

────────────────────────────────────────────────────────────────────────────────
Update git name with: git config user.name "Your Name"
Update git email with: git config user.email "you@example.com"
You can skip this check with --no-gitignore
Added .aider* to .gitignore
Aider v0.86.2
Main model: gpt-4o with diff edit format
Weak model: gpt-4o-mini
Git repo: .git with 308 files
Repo-map: using 4096 tokens, auto refresh

https://aider.chat/HISTORY.html#release-notes

Initial repo scan can be slow in larger repos, but only happens once.
Repo-map can't include
/home/runner/work/universal-or-strategy/universal-or-strategy/.claude/worktrees/
affectionate-franklin
Has it been deleted from the file system but not from git?
Repo-map can't include
/home/runner/work/universal-or-strategy/universal-or-strategy/.claude/worktrees/
sleepy-jepsen
Has it been deleted from the file system but not from git?
Repo-map can't include
/home/runner/work/universal-or-strategy/universal-or-strategy/AntigravityMobile
Has it been deleted from the file system but not from git?
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 0.2 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 0.5 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 1.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 2.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 4.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 8.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 16.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.
Retrying in 32.0 seconds...
litellm.RateLimitError: RateLimitError: OpenAIException - You exceeded your
current quota, please check your plan and billing details. For more information
on this error, read the docs:
https://platform.openai.com/docs/guides/error-codes/api-errors.
The API provider has rate limited you. Try again later or check your quotas.

https://platform.openai.com/docs/guides/error-codes/api-errors

Copy link
Copy Markdown

@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: 2

🧹 Nitpick comments (1)
.github/workflows/gemini-pr-audit.yml (1)

43-44: Prefer repository variables for GCP coordinates.

Hard-coding the project and region here means every environment move or fork requires a workflow edit. Repository or environment variables keep this reusable without changing code.

♻️ Suggested change
-          GCP_PROJECT_ID: "project-263b6139-6893-4788-995"
-          GCP_REGION: "us-east4"
+          GCP_PROJECT_ID: "${{ vars.GCP_PROJECT_ID }}"
+          GCP_REGION: "${{ vars.GCP_REGION }}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/gemini-pr-audit.yml around lines 43 - 44, Replace the
hard-coded GCP_PROJECT_ID and GCP_REGION values with references to repository
variables so the workflow is reusable; update the env entries to use GitHub
Actions variable expressions like GCP_PROJECT_ID: ${{ vars.GCP_PROJECT_ID }} and
GCP_REGION: ${{ vars.GCP_REGION }} (or switch to secrets if these should be
secret) in place of the literal strings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/gemini-pr-audit.yml:
- Around line 58-77: The audit prompt hardcodes "Build 973", "Meta-Purge", and
"AccountOrders.cs" causing mismatches for PRs (e.g., Build 972); update the
prompt construction (the prompt template stored in the prompt variable) to
derive target build and scope dynamically from PR metadata (e.g., use
placeholders like ${prBuildTag}, ${prFilesChanged}, or ${prTitle} instead of
literal "Build 973"/"AccountOrders.cs"), or fall back to GEMINI.md-driven checks
when metadata is absent; ensure the MISSION BRIEF lines (Build tag, target
file/scope, and checklist items like ASCII-ONLY/stateLock) are populated from
those dynamic values so the automated audit aligns with the actual PR under
review.
- Line 9: The workflow references the retired model identifier
gemini-1.5-pro-002 while naming "Gemini 3.1 Pro"; update every occurrence of the
retired model string (e.g., the model arguments/inputs where gemini-1.5-pro-002
is used) to the supported identifier gemini-3.1-pro-preview so the job actually
targets Gemini 3.1 Pro (ensure you change all instances in the file where the
model name appears, including model: or args: fields that pass the model id).

---

Nitpick comments:
In @.github/workflows/gemini-pr-audit.yml:
- Around line 43-44: Replace the hard-coded GCP_PROJECT_ID and GCP_REGION values
with references to repository variables so the workflow is reusable; update the
env entries to use GitHub Actions variable expressions like GCP_PROJECT_ID: ${{
vars.GCP_PROJECT_ID }} and GCP_REGION: ${{ vars.GCP_REGION }} (or switch to
secrets if these should be secret) in place of the literal strings.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 50e5c8b6-1776-49e8-8c88-1a96d6508a9b

📥 Commits

Reviewing files that changed from the base of the PR and between c9d5ec0 and 33cae56.

📒 Files selected for processing (1)
  • .github/workflows/gemini-pr-audit.yml

Comment thread .github/workflows/gemini-pr-audit.yml Outdated
Comment thread .github/workflows/gemini-pr-audit.yml Outdated
Comment on lines +58 to +77
const prompt = `You are the Lead Software Architect (Gemini 3.1 Pro) performing an automated forensic audit.
Your task is to analyze the following PR diff against our project's GEMINI.md standards.

MISSION BRIEF:
- Verify the Build 973 Meta-Purge Fix.
- Ensure the FSM-Aware Guard in AccountOrders.cs correctly rescues PendingCancel specs.
- Verify BUILD_TAG is 973.
- Check for ASCII-ONLY string literals.
- Verify that stateLock is used for all state mutations.

GEMINI.md context:
${geminiMdContent}

Here is the pull request diff:
PR DIFF:
${diffContent}

Provide a systematic review of the changes:
1. Evaluate strict adherence to the standards (e.g., FSM replace pattern vs cancel+submit, lock guards, headless UI rules).
2. Point out any violations of the standard with specific file and line context.
3. If the code is perfectly aligned, state that it passes the Zero-Regression Bot Audit.

Be thorough, precise, and uncompromising on the rules.`;
Provide a systematic review:
1. Evaluate adherence to Build 973 specifications.
2. Identify any logic gaps or safety violations.
3. Final Verdict: PASS or FAIL.`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Audit brief is targeting a different change than this PR.

This prompt now audits a Build 973 Meta-Purge / AccountOrders.cs scenario, while the PR is scoped to Build 972 follower-order loss repair. That can produce false PASS/FAIL results and miss regressions in Move-Grace suppression, expected-position repair, and precise cascade matching.

🛠️ Suggested prompt alignment
-            MISSION BRIEF:
-            - Verify the Build 973 Meta-Purge Fix.
-            - Ensure the FSM-Aware Guard in AccountOrders.cs correctly rescues PendingCancel specs.
-            - Verify BUILD_TAG is 973.
-            - Check for ASCII-ONLY string literals.
-            - Verify that stateLock is used for all state mutations.
+            MISSION BRIEF:
+            - Verify the Build 972 follower order loss repair.
+            - Ensure Move-Grace suppression prevents cleanup while a master move is in progress.
+            - Ensure expectedPositions are re-asserted after replacement flows.
+            - Ensure cascade cleanup uses precise matching and avoids collateral removals.
+            - Verify BUILD_TAG is 972.

-            Provide a systematic review:
-            1. Evaluate adherence to Build 973 specifications.
+            Provide a systematic review:
+            1. Evaluate adherence to Build 972 specifications.
             2. Identify any logic gaps or safety violations.
             3. Final Verdict: PASS or FAIL.`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const prompt = `You are the Lead Software Architect (Gemini 3.1 Pro) performing an automated forensic audit.
Your task is to analyze the following PR diff against our project's GEMINI.md standards.
MISSION BRIEF:
- Verify the Build 973 Meta-Purge Fix.
- Ensure the FSM-Aware Guard in AccountOrders.cs correctly rescues PendingCancel specs.
- Verify BUILD_TAG is 973.
- Check for ASCII-ONLY string literals.
- Verify that stateLock is used for all state mutations.
GEMINI.md context:
${geminiMdContent}
Here is the pull request diff:
PR DIFF:
${diffContent}
Provide a systematic review of the changes:
1. Evaluate strict adherence to the standards (e.g., FSM replace pattern vs cancel+submit, lock guards, headless UI rules).
2. Point out any violations of the standard with specific file and line context.
3. If the code is perfectly aligned, state that it passes the Zero-Regression Bot Audit.
Be thorough, precise, and uncompromising on the rules.`;
Provide a systematic review:
1. Evaluate adherence to Build 973 specifications.
2. Identify any logic gaps or safety violations.
3. Final Verdict: PASS or FAIL.`;
const prompt = `You are the Lead Software Architect (Gemini 3.1 Pro) performing an automated forensic audit.
Your task is to analyze the following PR diff against our project's GEMINI.md standards.
MISSION BRIEF:
- Verify the Build 972 follower order loss repair.
- Ensure Move-Grace suppression prevents cleanup while a master move is in progress.
- Ensure expectedPositions are re-asserted after replacement flows.
- Ensure cascade cleanup uses precise matching and avoids collateral removals.
- Verify BUILD_TAG is 972.
GEMINI.md context:
${geminiMdContent}
PR DIFF:
${diffContent}
Provide a systematic review:
1. Evaluate adherence to Build 972 specifications.
2. Identify any logic gaps or safety violations.
3. Final Verdict: PASS or FAIL.`;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/gemini-pr-audit.yml around lines 58 - 77, The audit prompt
hardcodes "Build 973", "Meta-Purge", and "AccountOrders.cs" causing mismatches
for PRs (e.g., Build 972); update the prompt construction (the prompt template
stored in the prompt variable) to derive target build and scope dynamically from
PR metadata (e.g., use placeholders like ${prBuildTag}, ${prFilesChanged}, or
${prTitle} instead of literal "Build 973"/"AccountOrders.cs"), or fall back to
GEMINI.md-driven checks when metadata is absent; ensure the MISSION BRIEF lines
(Build tag, target file/scope, and checklist items like ASCII-ONLY/stateLock)
are populated from those dynamic values so the automated audit aligns with the
actual PR under review.

@github-actions
Copy link
Copy Markdown

🤖 Kilo Code PR Auditor (Gemini 3.1 Pro via Vertex AI)

⚠️ Kilo Auditor Failed to Execute: [VertexAI.ClientError]: got status: 404 Not Found. {"error":{"code":404,"message":"Publisher Model projects/project-263b6139-6893-4788-995/locations/us-east4/publishers/google/models/gemini-1.5-pro-002 was not found or your project does not have access to it. Please ensure you are using a valid model version. For more information, see: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versions","status":"NOT_FOUND"}}

@github-actions
Copy link
Copy Markdown

────────────────────────────────────────────────────────────────────────────────
Update git name with: git config user.name "Your Name"
Update git email with: git config user.email "you@example.com"
You can skip this check with --no-gitignore
Added .aider* to .gitignore
Aider v0.86.2
Main model: gpt-4o with diff edit format
Weak model: gpt-4o-mini
Git repo: .git with 308 files
Repo-map: using 4096 tokens, auto refresh

https://aider.chat/HISTORY.html#release-notes

Initial repo scan can be slow in larger repos, but only happens once.
Repo-map can't include
/home/runner/work/universal-or-strategy/universal-or-strategy/.claude/worktrees/
affectionate-franklin
Has it been deleted from the file system but not from git?
Repo-map can't include
/home/runner/work/universal-or-strategy/universal-or-strategy/.claude/worktrees/
sleepy-jepsen
Has it been deleted from the file system but not from git?
Repo-map can't include
/home/runner/work/universal-or-strategy/universal-or-strategy/AntigravityMobile
Has it been deleted from the file system but not from git?
litellm.BadRequestError: OpenAIException - You didn't provide an API key. You
need to provide your API key in an Authorization header using Bearer auth (i.e.
Authorization: Bearer YOUR_KEY), or as the password field (with blank username)
if you're accessing the API from your browser and are prompted for a username
and password. You can obtain an API key from
https://platform.openai.com/account/api-keys.

https://platform.openai.com/account/api-keys

Copy link
Copy Markdown

@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: 2

🧹 Nitpick comments (1)
.github/workflows/kilo-pr-audit.yml (1)

5-5: Reuse the existing auditor comment on synchronize.

Every new push will hit createComment, so active PRs will accumulate one full Kilo audit per commit. Use a stable marker and updateComment when a previous auditor comment already exists.

One way to dedupe comments
-            await github.rest.issues.createComment({
-              owner: context.repo.owner,
-              repo: context.repo.repo,
-              issue_number: context.issue.number,
-              body: "### 🤖 Kilo Code PR Auditor (Gemini 3.1 Pro via Vertex AI)\n\n" + reviewText
-            });
+            const marker = '<!-- kilo-pr-audit -->';
+            const body = `${marker}\n### 🤖 Kilo Code PR Auditor (Gemini 3.1 Pro via Vertex AI)\n\n${reviewText}`;
+            const { data: comments } = await github.rest.issues.listComments({
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              issue_number: context.issue.number,
+            });
+            const existing = comments.find(
+              (comment) => comment.user?.type === 'Bot' && comment.body?.includes(marker)
+            );
+
+            if (existing) {
+              await github.rest.issues.updateComment({
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                comment_id: existing.id,
+                body,
+              });
+            } else {
+              await github.rest.issues.createComment({
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                issue_number: context.issue.number,
+                body,
+              });
+            }

Also applies to: 100-105

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/kilo-pr-audit.yml at line 5, Currently the workflow always
calls createComment on the auditor output which causes duplicate comments on
each synchronize event; modify the logic that posts the audit comment to instead
search for an existing comment by a stable marker (e.g., a unique HTML comment
or token used in the auditor body) and call updateComment when found, falling
back to createComment only if no existing comment exists; ensure this change is
applied to the comment-posting steps referenced around the existing
createComment usage so synchronize events update the prior audit rather than
appending a new one.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/kilo-pr-audit.yml:
- Around line 58-81: The prompt construction in the workflow builds a single
interpolated string named prompt that embeds untrusted GEMINI.md and pr.diff
content directly (variables geminiMdContent and diffContent), which permits
prompt-injection; fix by removing direct interpolation and instead pass
untrusted inputs as separate structured data to the auditor process (e.g.,
provide geminiMdContent and diffContent via files, CLI args, or JSON payload),
sanitize or validate them for length and allowed characters (reject control
sequences/embedded instructions), and ensure the auditor uses a fixed system
instruction (not influenced by contributors) while treating
geminiMdContent/diffContent only as data; update the code that constructs or
sends prompt to the auditor (the prompt variable and its consumer) to follow
this separation and sanitization approach.
- Around line 8-9: The workflow job "kilo-audit" currently hard-codes the Build
973 Meta-Purge checklist (mentions "Build 973", "AccountOrders.cs",
"Propagation.cs") and enforces "C#-only" rules, causing false positives on
unrelated PRs; update .github/workflows/kilo-pr-audit.yml to generate the audit
prompt dynamically by extracting the PR title/body and the list of changed
files, remove the fixed references to Build 973/AccountOrders.cs/Propagation.cs,
and relax the language that restricts checks to C# so the auditor scopes checks
based on the PR's actual files and description; ensure the prompt-building logic
falls back to a generic checklist when no specific files or keywords are
detected.

---

Nitpick comments:
In @.github/workflows/kilo-pr-audit.yml:
- Line 5: Currently the workflow always calls createComment on the auditor
output which causes duplicate comments on each synchronize event; modify the
logic that posts the audit comment to instead search for an existing comment by
a stable marker (e.g., a unique HTML comment or token used in the auditor body)
and call updateComment when found, falling back to createComment only if no
existing comment exists; ensure this change is applied to the comment-posting
steps referenced around the existing createComment usage so synchronize events
update the prior audit rather than appending a new one.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 023c82b6-1bd7-40d6-9412-47cafbc4e9af

📥 Commits

Reviewing files that changed from the base of the PR and between 33cae56 and 163f239.

📒 Files selected for processing (1)
  • .github/workflows/kilo-pr-audit.yml

Comment thread .github/workflows/kilo-pr-audit.yml Outdated
Comment on lines +8 to +9
kilo-audit:
name: Kilo 3.1 Pro (Meta-Purge Audit)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Generalize the audit scope instead of hard-coding the Build 973 Meta-Purge checklist.

This workflow runs on every PR, but the prompt always asks the model to verify a specific Build 973 fix in AccountOrders.cs/Propagation.cs and to enforce C#-only rules. On unrelated PRs, that will produce false FAILs and noisy findings. Drive the audit from the current PR’s title/body and changed files instead of baking one incident’s playbook into the global auditor.

Also applies to: 61-69

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/kilo-pr-audit.yml around lines 8 - 9, The workflow job
"kilo-audit" currently hard-codes the Build 973 Meta-Purge checklist (mentions
"Build 973", "AccountOrders.cs", "Propagation.cs") and enforces "C#-only" rules,
causing false positives on unrelated PRs; update
.github/workflows/kilo-pr-audit.yml to generate the audit prompt dynamically by
extracting the PR title/body and the list of changed files, remove the fixed
references to Build 973/AccountOrders.cs/Propagation.cs, and relax the language
that restricts checks to C# so the auditor scopes checks based on the PR's
actual files and description; ensure the prompt-building logic falls back to a
generic checklist when no specific files or keywords are detected.

Comment thread .github/workflows/kilo-pr-audit.yml Outdated
@github-actions
Copy link
Copy Markdown

⚠️ Codex Auditor Failed to Execute: OpenAI API error: {"error":{"message":"You didn't provide an API key. You need to provide your API key in an Authorization header using Bearer auth (i.e. Authorization: Bearer YOUR_KEY), or as the password field (with blank username) if you're accessing the API from your browser and are prompted for a username and password. You can obtain an API key from https://platform.openai.com/account/api-keys.","type":"invalid_request_error","param":null,"code":null}}

@github-actions
Copy link
Copy Markdown

🤖 Kilo Code PR Auditor (Gemini 3.1 Pro via Vertex AI)

⚠️ Kilo Auditor Failed to Execute: [VertexAI.ClientError]: got status: 404 Not Found. {"error":{"code":404,"message":"Publisher Model projects/project-263b6139-6893-4788-995/locations/us-central1/publishers/google/models/gemini-1.5-pro-002 was not found or your project does not have access to it. Please ensure you are using a valid model version. For more information, see: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versions","status":"NOT_FOUND"}}

Copy link
Copy Markdown

@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: 5

🧹 Nitpick comments (2)
.github/workflows/kilo-pr-audit.yml (2)

38-38: Pin the Vertex AI SDK version for reproducible builds.

Installing @google-cloud/vertexai without a version specifier means the workflow may break unpredictably when a new major version is released.

📦 Suggested fix
-      - name: Install Vertex AI SDK
-        run: npm install `@google-cloud/vertexai`
+      - name: Install Vertex AI SDK
+        run: npm install `@google-cloud/vertexai`@1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/kilo-pr-audit.yml at line 38, The workflow currently
installs `@google-cloud/vertexai` without a version, which risks unpredictable
breaks; update the run step that contains "run: npm install
`@google-cloud/vertexai`" to pin a specific version (or an exact semver like
`@google-cloud/vertexai`@1.2.3 or a fixed range) so builds are reproducible and
update the lockfile if present; ensure the modified run line uses the chosen
pinned package specifier.

43-44: Move GCP_PROJECT_ID to a repository secret.

Hard-coding the GCP project ID in the workflow file exposes infrastructure details in version control and makes environment changes difficult. Use a secret instead.

🔒 Suggested fix
         env:
-          GCP_PROJECT_ID: "project-263b6139-6893-4788-995"
-          GCP_REGION: "us-central1"
+          GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
+          GCP_REGION: ${{ vars.GCP_REGION || 'us-central1' }}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/kilo-pr-audit.yml around lines 43 - 44, Replace the
hard-coded GCP_PROJECT_ID in kilo-pr-audit.yml with a repository secret
reference and add that secret in the repo settings; specifically, remove the
literal "project-263b6139-6893-4788-995" assigned to GCP_PROJECT_ID, create a
repo secret named GCP_PROJECT_ID via GitHub Settings -> Secrets, and update the
workflow to read the value from the secret (keeping GCP_REGION as is) so the
workflow uses the secret-provided project ID at runtime.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/codex-audit.yml:
- Around line 34-35: The workflow currently reads the raw PR diff into
diffContent and later incorporates it into prompt/codexBrain; before building
prompt, filter and redact the diff: apply a path allowlist (only include
files/extensions you want analyzed), remove or mask lines matching secret
patterns (API keys, tokens, private keys, email/PII regexes), and strip large
binary/fixture blocks; implement this sanitization as a function (e.g.,
sanitizeDiff or redactDiff) and call it on diffContent before assigning to
codexBrain or interpolating into prompt so no sensitive data is sent
off-platform.
- Around line 35-40: Replace the direct workspace read of the mission brief (the
fs.readFileSync call that assigns codexBrain from
'.agent/brain/codex_pr25_audit.md') with a fetch from the repository base ref:
use the GitHub API / Octokit content endpoint (or actions/github client) to GET
the file content with ref = context.payload.pull_request.base.sha, decode and
assign it to codexBrain, and fall back to the existing default string only if
the API returns not found or an error; ensure the code references the same
filename and retains the codexBrain variable and error fallback logic.
- Around line 42-69: The prompt currently embeds the full ${diffContent} into
the chat-completions request (inside prompt) and posts directly via fetch using
model 'gpt-4o'; add a pre-send bounding step to avoid exceeding the model
context: check the length/token estimate of diffContent, and if it exceeds a
threshold, either truncate to a safe max, split into chunks (per-file or
fixed-size) and iterate requests, or pre-summarize the diff (using codexBrain or
a separate summarizer) before building prompt; ensure the logic runs before
constructing prompt and before the fetch call so the final prompt variable
always stays under the model limit and handle/report when chunking/summarizing
is used.

In @.github/workflows/kilo-pr-audit.yml:
- Line 94: The assignment to reviewText assumes
resp.response.candidates[0].content.parts[0].text exists; change this to
defensively access the nested structure (validate resp, resp.response,
resp.response.candidates is an array with length > 0, candidates[0].content and
content.parts is an array with length > 0) and fall back to a safe default
(e.g., empty string or a meaningful message) if any part is missing; implement
this in the code that sets reviewText (replace the direct access to
resp.response.candidates[0].content.parts[0].text) and consider wrapping parsing
in a try/catch to log unexpected shapes before using the fallback.
- Around line 84-86: The comment above the vertex_ai.getGenerativeModel call
incorrectly equates 'gemini-1.5-pro-002' with "Gemini 3.1 Pro (Kilo) engine";
update the comment (or remove it) to accurately reflect the actual model string
in the getGenerativeModel invocation (generativeModel and model:
'gemini-1.5-pro-002') so maintainers are not misled about generation/version,
e.g., replace the misleading text with the correct model name/version or a
neutral note that the string is the configured model ID.

---

Nitpick comments:
In @.github/workflows/kilo-pr-audit.yml:
- Line 38: The workflow currently installs `@google-cloud/vertexai` without a
version, which risks unpredictable breaks; update the run step that contains
"run: npm install `@google-cloud/vertexai`" to pin a specific version (or an exact
semver like `@google-cloud/vertexai`@1.2.3 or a fixed range) so builds are
reproducible and update the lockfile if present; ensure the modified run line
uses the chosen pinned package specifier.
- Around line 43-44: Replace the hard-coded GCP_PROJECT_ID in kilo-pr-audit.yml
with a repository secret reference and add that secret in the repo settings;
specifically, remove the literal "project-263b6139-6893-4788-995" assigned to
GCP_PROJECT_ID, create a repo secret named GCP_PROJECT_ID via GitHub Settings ->
Secrets, and update the workflow to read the value from the secret (keeping
GCP_REGION as is) so the workflow uses the secret-provided project ID at
runtime.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e140f5c1-d783-4666-94cb-6352f9df2895

📥 Commits

Reviewing files that changed from the base of the PR and between 163f239 and 4e54f30.

📒 Files selected for processing (2)
  • .github/workflows/codex-audit.yml
  • .github/workflows/kilo-pr-audit.yml

Comment thread .github/workflows/codex-audit.yml Outdated
Comment thread .github/workflows/codex-audit.yml Outdated
Comment on lines +35 to +40
let codexBrain = '';
try {
codexBrain = fs.readFileSync('.agent/brain/codex_pr25_audit.md', 'utf8');
} catch (e) {
codexBrain = 'No specific mission brief found. Perform a general forensic audit for race conditions and ASCII compliance.';
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In GitHub Actions, when a workflow runs on pull_requestand usesactions/checkout@v4 with the default ref, does the workspace contain the PR merge commit / PR contents instead of the base branch contents?

💡 Result:

Yes. On a pull_request-triggered workflow, actions/checkout@v4 with the default ref checks out the ref/SHA that triggered the event, and for pull_request that SHA/ref corresponds to GitHub’s PR merge branch (typically refs/pull/<n>/merge)—i.e., the synthetic merge commit containing the PR changes merged onto the base branch, not the base branch alone. [1][2] (docs.github.com)

Sources
[1] GitHub Docs – “Events that trigger workflows” (pull_request uses PR merge branch; GITHUB_SHA is the last merge commit). (docs.github.com)
[2] actions/checkout README – default ref is the ref/SHA for the triggering event; example shows how to checkout PR HEAD instead of merge commit. (github.com)

Citations:


🏁 Script executed:

# Check if the workflow file exists and examine the relevant lines
find . -name "codex-audit.yml" -type f

# Also check the structure around mission brief references
if [ -f ".github/workflows/codex-audit.yml" ]; then
  echo "=== Workflow file found ==="
  head -50 ".github/workflows/codex-audit.yml"
fi

# Check if the mission brief file exists
if [ -f ".agent/brain/codex_pr25_audit.md" ]; then
  echo "=== Mission brief file exists ==="
  ls -la ".agent/brain/codex_pr25_audit.md"
else
  echo "=== Mission brief file NOT found ==="
  find . -name "*codex*" -type f 2>/dev/null | head -20
fi

Repository: mkalhitti-cloud/universal-or-strategy

Length of output: 1626


🏁 Script executed:

# Check if there's more of the workflow script that shows how github API is used
grep -A 50 "actions/github-script" ".github/workflows/codex-audit.yml" | head -60

Repository: mkalhitti-cloud/universal-or-strategy

Length of output: 2164


Load the mission brief from a trusted ref, not the PR workspace.

Line 37 reads .agent/brain/codex_pr25_audit.md from the checked-out tree, allowing the PR author to modify the instructions that review their own patch. Fetch that file from the base branch instead using context.payload.pull_request.base.sha.

Suggested fix
-            let codexBrain = '';
-            try {
-              codexBrain = fs.readFileSync('.agent/brain/codex_pr25_audit.md', 'utf8');
-            } catch (e) {
+            let codexBrain = '';
+            try {
+              const mission = await github.rest.repos.getContent({
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                path: '.agent/brain/codex_pr25_audit.md',
+                ref: context.payload.pull_request.base.sha,
+              });
+              codexBrain = Buffer.from(mission.data.content, 'base64').toString('utf8');
+            } catch (e) {
               codexBrain = 'No specific mission brief found. Perform a general forensic audit for race conditions and ASCII compliance.';
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let codexBrain = '';
try {
codexBrain = fs.readFileSync('.agent/brain/codex_pr25_audit.md', 'utf8');
} catch (e) {
codexBrain = 'No specific mission brief found. Perform a general forensic audit for race conditions and ASCII compliance.';
}
let codexBrain = '';
try {
const mission = await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path: '.agent/brain/codex_pr25_audit.md',
ref: context.payload.pull_request.base.sha,
});
codexBrain = Buffer.from(mission.data.content, 'base64').toString('utf8');
} catch (e) {
codexBrain = 'No specific mission brief found. Perform a general forensic audit for race conditions and ASCII compliance.';
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/codex-audit.yml around lines 35 - 40, Replace the direct
workspace read of the mission brief (the fs.readFileSync call that assigns
codexBrain from '.agent/brain/codex_pr25_audit.md') with a fetch from the
repository base ref: use the GitHub API / Octokit content endpoint (or
actions/github client) to GET the file content with ref =
context.payload.pull_request.base.sha, decode and assign it to codexBrain, and
fall back to the existing default string only if the API returns not found or an
error; ensure the code references the same filename and retains the codexBrain
variable and error fallback logic.

Comment thread .github/workflows/codex-audit.yml Outdated
Comment on lines +42 to +69
const prompt = `You are Codex (GPT-4o), the Volume Laborer and Forensic Auditor.
Your task is to analyze the following PR diff against our project's forensic standards.

MISSION BRIEF:
${codexBrain}

PR DIFF:
${diffContent}

Provide a systematic P1/P2/P3 severity report:
1. P1 (Critical): Race conditions, ghost order risks, or thread-safety violations.
2. P2 (Warning): ASCII violations, logic gaps, or non-compliant FSM patterns.
3. P3 (Stylistic): Naming, metabolic elegance, and C# 8.0/NT8 efficiency.

Final Verdict: PASS or FAIL.`;

try {
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`
},
body: JSON.stringify({
model: 'gpt-4o',
messages: [{ role: 'user', content: prompt }],
temperature: 0.1
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

What are the current request/context limits for the OpenAI gpt-4o model on the Chat Completions API, and what error is returned when the input exceeds them?

💡 Result:

  • gpt-4o limits (Chat Completions API v1/chat/completions):

    • Context window (total tokens = input messages + output): 128,000 tokens [1]
    • Max output tokens per response: 16,384 tokens [1]
  • What happens if you exceed the context window:

    • The API returns HTTP 400 (Bad Request) / invalid_request_error, typically with code: "context_length_exceeded" and an error message of the form:
      This model's maximum context length is … tokens. However, you requested … tokens … Please reduce the length of the messages or completion.” [2][3]

Sources: [1] OpenAI model docs for gpt-4o limits, [2] OpenAI Developer Community example including code: context_length_exceeded, [3] OpenAI Developer Community example of the 400 error message format.


Bound the prompt size before calling the model.

Lines 48-49 inject the entire diff into one chat-completions request without size checks. The gpt-4o model has a 128,000 token context window; large PRs will exceed this limit and cause the API to return a 400 error. Truncate, chunk per file, or pre-summarize the diff before POSTing.

Minimal guardrail
+            const MAX_DIFF_CHARS = 120_000;
+            const boundedDiff =
+              diffContent.length > MAX_DIFF_CHARS
+                ? diffContent.slice(0, MAX_DIFF_CHARS) + '\n\n[diff truncated before upload]'
+                : diffContent;
+
             const prompt = `You are Codex (GPT-4o), the Volume Laborer and Forensic Auditor.
             Your task is to analyze the following PR diff against our project's forensic standards.
@@
             PR DIFF:
-            ${diffContent}
+            ${boundedDiff}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/codex-audit.yml around lines 42 - 69, The prompt currently
embeds the full ${diffContent} into the chat-completions request (inside prompt)
and posts directly via fetch using model 'gpt-4o'; add a pre-send bounding step
to avoid exceeding the model context: check the length/token estimate of
diffContent, and if it exceeds a threshold, either truncate to a safe max, split
into chunks (per-file or fixed-size) and iterate requests, or pre-summarize the
diff (using codexBrain or a separate summarizer) before building prompt; ensure
the logic runs before constructing prompt and before the fetch call so the final
prompt variable always stays under the model limit and handle/report when
chunking/summarizing is used.

Comment thread .github/workflows/kilo-pr-audit.yml Outdated
Comment thread .github/workflows/kilo-pr-audit.yml Outdated
@@ -85,12 +94,12 @@ jobs:
reviewText = resp.response.candidates[0].content.parts[0].text;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unsafe property access chain when parsing API response.

The response parsing assumes a specific nested structure (resp.response.candidates[0].content.parts[0].text). If the API returns an unexpected format (e.g., empty candidates array, content filtering), this will throw an unhandled exception.

🛡️ Suggested fix with defensive checks
-              reviewText = resp.response.candidates[0].content.parts[0].text;
+              const candidates = resp.response?.candidates;
+              if (candidates && candidates.length > 0 && candidates[0].content?.parts?.[0]?.text) {
+                reviewText = candidates[0].content.parts[0].text;
+              } else {
+                reviewText = "⚠️ **Kilo Auditor**: Received unexpected response format from Vertex AI.";
+              }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
reviewText = resp.response.candidates[0].content.parts[0].text;
const candidates = resp.response?.candidates;
if (candidates && candidates.length > 0 && candidates[0].content?.parts?.[0]?.text) {
reviewText = candidates[0].content.parts[0].text;
} else {
reviewText = "⚠️ **Kilo Auditor**: Received unexpected response format from Vertex AI.";
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/kilo-pr-audit.yml at line 94, The assignment to reviewText
assumes resp.response.candidates[0].content.parts[0].text exists; change this to
defensively access the nested structure (validate resp, resp.response,
resp.response.candidates is an array with length > 0, candidates[0].content and
content.parts is an array with length > 0) and fall back to a safe default
(e.g., empty string or a meaningful message) if any part is missing; implement
this in the code that sets reviewText (replace the direct access to
resp.response.candidates[0].content.parts[0].text) and consider wrapping parsing
in a try/catch to log unexpected shapes before using the fallback.

@github-actions
Copy link
Copy Markdown

⚠️ Codex Auditor Failed to Execute: OpenAI API error: {"error":{"message":"You didn't provide an API key. You need to provide your API key in an Authorization header using Bearer auth (i.e. Authorization: Bearer YOUR_KEY), or as the password field (with blank username) if you're accessing the API from your browser and are prompted for a username and password. You can obtain an API key from https://platform.openai.com/account/api-keys.","type":"invalid_request_error","param":null,"code":null}}

@github-actions
Copy link
Copy Markdown

🤖 Kilo Code PR Auditor (Gemini 3.1 Pro via Vertex AI)

⚠️ Kilo Auditor Failed to Execute: [VertexAI.ClientError]: got status: 404 Not Found. {"error":{"code":404,"message":"Publisher Model projects/project-263b6139-6893-4788-995/locations/us-central1/publishers/google/models/gemini-3.1-pro-preview was not found or your project does not have access to it. Please ensure you are using a valid model version. For more information, see: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versions","status":"NOT_FOUND"}}

@github-actions
Copy link
Copy Markdown

🤖 Antigravity Auto-Auditor (Gemini 3.1 Pro via Vertex AI)

⚠️ Gemini Auditor Failed to Execute: [VertexAI.ClientError]: got status: 404 Not Found. {"error":{"code":404,"message":"Publisher Model projects/project-263b6139-6893-4788-995/locations/us-central1/publishers/google/models/gemini-3.1-pro-preview was not found or your project does not have access to it. Please ensure you are using a valid model version. For more information, see: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versions","status":"NOT_FOUND"}}

@github-actions
Copy link
Copy Markdown

🤖 Antigravity Auto-Auditor (Gemini 3.1 Pro via Vertex AI)

⚠️ Gemini Auditor Failed to Execute: [VertexAI.ClientError]: got status: 404 Not Found. {"error":{"code":404,"message":"Publisher Model projects/project-263b6139-6893-4788-995/locations/us-central1/publishers/google/models/gemini-1.5-pro-002 was not found or your project does not have access to it. Please ensure you are using a valid model version. For more information, see: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versions","status":"NOT_FOUND"}}

@github-actions
Copy link
Copy Markdown

🤖 Kilo Code PR Auditor (Gemini 3.1 Pro via Vertex AI)

⚠️ Kilo Auditor Failed to Execute: [VertexAI.ClientError]: got status: 404 Not Found. {"error":{"code":404,"message":"Publisher Model projects/project-263b6139-6893-4788-995/locations/us-central1/publishers/google/models/gemini-1.5-pro-002 was not found or your project does not have access to it. Please ensure you are using a valid model version. For more information, see: https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versions","status":"NOT_FOUND"}}

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

Copy link
Copy Markdown
Owner Author

@mkalhitti-cloud mkalhitti-cloud left a comment

Choose a reason for hiding this comment

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

🤖 Gemini Review

This PR combines a large-scale refactoring of the REAPER logic with critical bug fixes for follower order handling. This makes a full review challenging, but here are my findings based on the provided focus areas:

1. ASCII-ONLY Compliance:

The changes appear to be compliant with the project's ASCII-only rule for string literals. No non-ASCII characters were found in the diff.

2. Thread-Safety:

The change in src/V12_002.SIMA.cs inside AddExpectedPositionDeltaLocked correctly uses Interlocked.Exchange. However, I cannot verify the thread safety of the new StampAccountFillGrace() method from the provided diff. Please ensure that any state mutations within that method are properly protected.

3. FSM Integrity for Follower Orders:

Given the scale of the REAPER refactoring, it is difficult to audit the FSM integrity for the follower order replace pattern from this diff alone. While the PR's goal is to fix follower order loss, the new implementation's adherence to the strict two-phase FSM described in GEMINI.md needs to be confirmed. I recommend adding a section to the PR description that explicitly maps the new code structure to the required FSM states to facilitate future reviews and maintenance.

Overall, the refactoring appears to align with the new file splitting protocol. My main concern is ensuring the new, distributed logic still rigorously adheres to the established concurrency and state machine patterns.

@mkalhitti-cloud
Copy link
Copy Markdown
Owner Author

AUDIT OVERRIDE - FULL FORENSIC SWEEP - PR #36

Executing line-by-line audit based on GEMINI.md standards.

File Line(s) Standard Finding Status
src/V12_002.Orders.Callbacks.AccountOrders.cs N/A ASCII-ONLY All characters are valid ASCII. PASS
src/V12_002.Symmetry.cs N/A ASCII-ONLY All characters are valid ASCII. PASS
src/V12_002.Symmetry.cs 73-107 LOCK INTEGRITY Missing lock(stateLock): The SymmetryGuardBeginDispatch method has a comment indicating the operation should be atomic under stateLock to prevent race conditions in dispatch creation. The lock is missing from the implementation. FAIL
src/V12_002.Orders.Callbacks.AccountOrders.cs 235-252 LOCK INTEGRITY Missing lock(stateLock): The comment on line 235 explicitly mentions using stateLock to prevent a TOCTOU window when snapshotting FSM state for replacement. The lock is not present, and the subsequent comment on line 242 (// V12.962 ACTOR: Direct field reads -- lock-free, serialized by _drainToken) appears to contradict the GEMINI.md mandate for using lock(stateLock). This is a critical risk for torn reads during state transitions. FAIL
src/V12_002.Orders.Callbacks.AccountOrders.cs 218-274 FSM SAFETY The Move-Sync FSM logic correctly transitions from PendingCancel to Submitting and avoids raw Cancel+Submit sequences. The implementation appears to adhere to the Build 947 standard. PASS
src/V12_002.Orders.Callbacks.AccountOrders.cs 230-236 REAPER REPAIR Incomplete REAPER Routing: The "Fill-during-gap" guard correctly identifies a master fill event. However, it only logs a message and removes the FSM spec. It fails to route the follower order to the REAPER repair logic as required, creating a risk of orphaned positions. The execution path is prematurely terminated. FAIL

Summary of Critical Failures:

  1. Lock Integrity: Two critical lock(stateLock) violations were found. These create a high risk of race conditions, inconsistent state, and strategy failure under concurrent load.
  2. REAPER Routing: The REAPER repair path for fills during the cancel/replace gap is not implemented, only commented. This will lead to desynchronized follower positions.

These failures require immediate remediation before this PR can be considered for merging.

@mkalhitti-cloud
Copy link
Copy Markdown
Owner Author

PR #36 Full Forensic Sweep

Standards: GEMINI.md + .agent/standards_manifesto.md
Head: 43448895559cab8d96177a8f5d8824e43c9d1c41
Off-diff override target included: src/V12_002.Symmetry.Replace.cs

ASCII-ONLY

Area File:Line Standard Result Evidence Risk
Diff string literals PR diff (*.cs, *.yml, *.py, *.md) ASCII-only C# / string literal safety PASS Diff-scoped added-line scan found no non-ASCII bytes in added string-bearing lines. No Build 936-style compiler break found in changed literals.
Gate script coverage check_ascii.py:1-22 ASCII-only enforcement must cover the changed scope WARN Script only scans a fixed file list by raw bytes and omits new split files (REAPER.Repair, REAPER.NakedStop) plus workflow/docs scope. Future Unicode regressions can false-pass the gate.

LOCK INTEGRITY

Area File:Line Standard Result Evidence Risk
Shared dict reads src/V12_002.Orders.Callbacks.AccountOrders.cs:95-101 Every shared-state touch must be under lock(stateLock) FAIL entryOrders, stopOrders, and target1Orders-target5Orders are read with no explicit lock(stateLock). Multi-dict matching can observe torn or stale state.
Cancel callback cleanup src/V12_002.Orders.Callbacks.AccountOrders.cs:199-205 Same FAIL entryOrders.TryRemove(...) and expectedPositions.TryGetValue(...) execute with no explicit lock. Shared state mutation/read outside written standard.
FSM state transition src/V12_002.Orders.Callbacks.AccountOrders.cs:233-262 Same FAIL activePositions read, fsm.PendingQty/PendingPrice read, and fsm.State = Submitting all occur without lock(stateLock), despite the nearby comment claiming otherwise. TOCTOU window in the cancel-confirm path.
Target FSM removal src/V12_002.Orders.Callbacks.AccountOrders.cs:292-303 Same FAIL _followerTargetReplaceSpecs.TryRemove(...) is unlocked. Target replace bookkeeping can drift under concurrent callbacks.
Expected-position rollback src/V12_002.Orders.Callbacks.AccountOrders.cs:321-330 Same FAIL Calls DeltaExpectedPositionLocked(...), but the helper body in src/V12_002.SIMA.cs:121-128 contains no lock(stateLock). Helper name masks non-compliance.
Cascade cleanup helpers src/V12_002.Orders.Callbacks.AccountOrders.cs:372-382 Same FAIL CleanupPosition(...) and SymmetryGuardForgetEntry(...) mutate shared dictionaries via helpers that are not actually locked. Cascading remove path can desync tracked state.
Master-replace suppression block src/V12_002.Orders.Callbacks.AccountOrders.cs:450-477 Same FAIL _followerReplaceSpecs read plus expectedPositions / dispatch-sync mutation occur without explicit lock(stateLock). Race remains in the master-cancel cascade path.
Target dict cleanup src/V12_002.Symmetry.Replace.cs:41-50 Same FAIL dict.TryRemove(...) executes with no explicit lock. Target dictionary can diverge from broker state.
Replacement dict write src/V12_002.Symmetry.Replace.cs:74-87 Same FAIL Replacement order is submitted and dict[fleetEntryName] = replacement is written with no lock(stateLock). Bookkeeping write is unguarded.
PositionInfo mutation src/V12_002.Symmetry.Replace.cs:102-105 Same FAIL pos.EntryFilled and pos.RemainingContracts mutate unlocked even though the comment says they must be inside stateLock. Direct contradiction between comment and implementation.
Follower-resolution reads src/V12_002.Symmetry.Replace.cs:142-167 Same FAIL symmetryPendingFollowerFills cleanup and activePositions.TryGetValue(...) occur with no stateLock. Pending-fill resolution can race active position updates.
Dispatch map mutation src/V12_002.Symmetry.Replace.cs:212-219 Same FAIL Dispatch/pending-fill maps mutate under ctx.Sync only, not stateLock. Does not satisfy the written lock rule.
Prune path reads src/V12_002.Symmetry.Replace.cs:227-262 Same FAIL activePositions.ContainsKey(...) is executed under ctx.Sync; comment again claims stateLock intent, but none exists. State visibility depends on informal locking.
Misleading helper names src/V12_002.SIMA.cs:73-128 *Locked helpers must actually lock FAIL AddOrUpdateExpectedPositionLocked, SetExpectedPositionLocked, and DeltaExpectedPositionLocked contain no lock(stateLock). Call sites look compliant when they are not.

FSM SAFETY

Area File:Line Standard Result Evidence Risk
Raw cancel+submit ban src/V12_002.Orders.Callbacks.Propagation.cs:374-425 No raw follower Cancel() + Submit() PASS PropagateFollowerEntryReplace(...) records _followerReplaceSpecs, sets PendingCancel, and sends only acct.Cancel(...). The old direct replace anti-pattern is not present in the focused Build 947 path.
Two-phase FSM src/V12_002.Orders.Callbacks.AccountOrders.cs:225-284 PendingCancel -> confirm -> Submitting -> submit PASS Cancel confirm matches CancellingOrderId, advances to Submitting, then schedules SubmitFollowerReplacement(...). Core FSM shape is intact.
Atomicity claim src/V12_002.Orders.Callbacks.AccountOrders.cs:247-262 Snapshot/state transition must be protected FAIL Comment says snapshot + state transition happen under stateLock, but code is lock-free. Written standard and implementation diverge in the most sensitive FSM block.
Cascade suppression src/V12_002.Orders.Callbacks.AccountOrders.cs:405-455 No raw master-cancel teardown during replace PASS New master-replace detection and in-flight FSM guard suppress destructive cascade cleanup. Fixes the prior chart-drag teardown failure mode.
Replacement sync rollback src/V12_002.Orders.Callbacks.Propagation.cs:442-497 Expected-position sync must survive submit failure PASS Code re-asserts expectedPositions before submit and rolls the delta back on submit exception. Replacement bookkeeping is better than the old gap path.
Master signal lookup src/V12_002.Orders.Callbacks.Propagation.cs:344-350 Match logic should avoid accidental cross-signal capture WARN Master lookup still uses bidirectional Contains(...), while later cascade cleanup uses anchored matching. Edge-case signal aliasing remains possible.

REAPER REPAIR

Area File:Line Standard Result Evidence Risk
Fill-during-gap handoff src/V12_002.Orders.Callbacks.AccountOrders.cs:231-244 If master filled during gap, route follower to REAPER repair FAIL Branch logs, removes FSM spec, and returns. It does not enqueue _reaperRepairQueue or call ProcessReaperRepairQueue(). Handoff to REAPER is implicit, not explicit, under the stated standard.
Later REAPER enqueue src/V12_002.REAPER.Audit.cs:73-131 REAPER must eventually detect actualQty == 0 && expectedQty != 0 PASS Once fill-grace / sync-pending clears, audit loop enqueues repair via _reaperRepairQueue.Enqueue(acct.Name). Delayed repair path exists.
Fill-grace support src/V12_002.SIMA.cs:84-88 Gap handling should suppress false REAPER churn after non-zero expected sync PASS New StampAccountFillGrace(accountName) call opens per-account grace when expected position becomes non-zero. Supports the delayed REAPER model.
Submit-time race guard src/V12_002.REAPER.Repair.cs:164-181 REAPER repair must recheck state before submit PASS Repair re-reads expectedPositions and aborts if it dropped to 0 before submit. Prevents stale repair orders from being sent.
REAPER split protocol src/V12_002.REAPER.cs delete 169-781, src/V12_002.REAPER.Repair.cs:1-207, src/V12_002.REAPER.NakedStop.cs:1-79 Splits over 50 lines must use a Python extractor script FAIL PR lands a 613-line REAPER extraction but the diff contains no scripts/*split.py extractor or parity-check artifact. The new mandatory split rule is not evidenced by the split that needs it most.

TOOLING AND ARTIFACT SWEEP

Area File:Line Standard Result Evidence Risk
Dead code gate scripts/dead_code_scan.py:1-103 PR gate should fail on dead private methods PASS Local run: [DEAD CODE SCAN] PASS -- 226 private methods checked, 0 dead. Gate behavior matches the new standard.
Static finding report quality scripts/build974_findings.txt:1-126 Audit artifacts should be reviewer-grade evidence WARN Report flags obvious framework/event false positives such as OnAccountOrderUpdate and ReaperLoop as zero-caller methods, while the live dead-code gate passes. Report can mislead reviewers if treated as ground truth.
Delegate trace quality scripts/zero_caller_trace.py:1-59 and scripts/trace_results.md:1-143 Trace artifacts should distinguish calls from comments/strings WARN Regex records comment and string matches; generated markdown contains repeated comment/string hits instead of only real delegate bindings. Trace output is noisy and not strong audit evidence.
Binary text artifacts binary_check.txt, pr_comments.json, scripts/trace_results.txt Repo artifacts should not land as opaque binary blobs WARN All three files are UTF-16LE BOM (FF FE) and Git reports them as binary diffs. Reviewability and tooling compatibility are reduced.
Temp artifact tmp_linecounts.txt:1-52 Keep generated temp files out of PRs unless required WARN Pure line-count inventory with no runtime effect. Adds review noise without behavioral value.
Workflow cleanup .github/workflows/codex-audit.yml, .github/workflows/gemini-pr-audit.yml Repo hygiene / stale automation cleanup PASS Old auto-auditor workflows are deleted cleanly. No strategy runtime risk.
Metadata and docs GEMINI.md, INFRASTRUCTURE_PROTOCOL.md, docs/audits/LIVE_FREEZE_FORENSIC_BRIEF_2026_03_09.md, src/V12_002.Constants.cs, src/V12_002.cs Non-runtime changes should stay scoped PASS These edits are doc/version updates only; no additional runtime logic beyond the standards text. None beyond reviewer noise.
Solution addition universal-or-strategy.sln:1-24 New project plumbing must build cleanly PASS dotnet build universal-or-strategy.sln -nologo succeeded with 0 errors / 0 warnings. No build regression from the new solution file.

PRECHECK EVIDENCE

Check Result Evidence
Build PASS dotnet build universal-or-strategy.sln -nologo -> succeeded, 0 errors, 0 warnings
Dead code gate PASS python scripts/dead_code_scan.py -> PASS, 226 private methods checked
Diff ASCII probe PASS Added string-bearing lines across changed .cs, .yml, .py, .md files contained no non-ASCII bytes

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