Bug fix for first_lock_order_violation in breaker.rs: brace characters inside string, char, and raw-string literals were corrupting the body-boundary scanner, causing ABBA lock-order violations to go undetected (returned None when they should have returned Some).

Symptoms

  • first_lock_order_violation(src) returns None (no violation detected) even when a function contains both an order-row lock and a config-row lock in the wrong order.
  • Trigger: any Rust source that contains a { or } character inside a string literal (e.g. let label = "}";) before the first lock keyword in a function body.

Root Cause

The §3.4 structural scanner in breaker.rs tracks function body boundaries by walking the raw source text character by character and incrementing/decrementing a depth counter on { and }. If a literal such as "}" appears before the actual closing brace of a function body, the counter reaches zero prematurely and the scanner exits that function’s body early, never reaching the lock keywords.

Fix

Added neutralize_literal_braces(src: &str) -> String — a single-pass char state machine that produces a byte-length-identical copy of src where every { or } inside a string literal, char literal, or raw string is replaced with a space.

State machine handles:

  • "..." double-quoted strings with \" and \\ escape sequences
  • '...' char literals with \' and \\ escape sequences
  • Raw strings: r"...", r#"..."#, r##"..."## (arbitrary # nesting depth, matched on opening count)

The function is called once at the top of first_lock_order_violation; the neutralized copy is used only for body-boundary depth-counting. The original src continues to be passed unchanged to the function-name extraction regex and to the SQL keyword (lock) detection, so string-literal content does not affect lock detection.

For Agents

neutralize_literal_braces lives in crates/polymarket-fetch/src/pmv2/autotrade/breaker.rs. The function must be kept byte-length-preserving (same .len()) so that any future extension that maps character positions back to the original src does not need offset translation.

Also Fixed: Spurious #[allow(dead_code)]

Removed the #[allow(dead_code)] annotation from bump_breaker_count in crates/polymarket-fetch/src/pmv2/repo.rs.

The function is fully reachable:

scheduled_run
  → run_pmv2_positions
    → run_autotrade_entry
      → run_entry
        → submit_live
          → breaker::bump_breaker
            → repo::bump_breaker_count

The annotation was a leftover from the original Task-5 extraction, when the call chain had not yet been wired end-to-end. It is now dead noise and could mask a real dead-code regression if the chain were later broken.

Regression Tests Added

Three tests added to the #[cfg(test)] block in breaker.rs:

sql_in_double_quoted_strings_is_still_detected

Guard that SQL keywords inside normal "..." strings are still detected after the fix (the neutralization applies only to brace characters, not to the SQL keyword scan which operates on the original src).

unbalanced_brace_in_string_before_locks_is_detected

let label = "}";
// ... later: order lock then config lock

Previously returned None. After the fix returns Some(fn_name).

unbalanced_brace_in_raw_string_before_locks_is_detected

let s = r#"a } b"#;
// ... later: order lock then config lock

Previously returned None. After the fix returns Some(fn_name).

Test scope

These tests exercise the scanner on synthetic snippets. The existing integration test (lock_order_is_correct_in_all_autotrade_files) still reads every real source file in src/pmv2/autotrade/*.rs plus src/pmv2/repo.rs and asserts no violation — it remains the live guard against accidental regressions in production code.

Gate

285 tests passed, 0 failed, exit 0.