Skip to content

ltm: clarify or eliminate the unreachable MostlyBalancing tie-break in LoopPolarity::from_runtime_scores #506

Description

@bpowers

Summary

LoopPolarity::from_runtime_scores in src/simlin-engine/src/ltm/types.rs:203-258 classifies a loop's runtime polarity from its loop_score series. The (true, true) arm reads:

(true, true) => {
    if confidence >= POLARITY_CONFIDENCE_THRESHOLD {
        if positive_sum > negative_sum_abs {
            LoopPolarity::MostlyReinforcing
        } else {
            // When magnitudes tie at >= threshold confidence the
            // ratio is 0, which violates the threshold check above
            // for any threshold > 0.  This branch therefore covers
            // the strictly-dominant balancing case.
            LoopPolarity::MostlyBalancing
        }
    } else {
        LoopPolarity::Undetermined
    }
}

The comment correctly notes that the inner else branch (where positive_sum == negative_sum_abs) is unreachable when POLARITY_CONFIDENCE_THRESHOLD > 0, because an exact magnitude tie implies ratio = 0 => confidence = 0, and the outer if would have already short-circuited to Undetermined.

But this means the inner else branch is never actually reached for the tie case -- it only fires when negative_sum_abs > positive_sum strictly, i.e. the "balancing dominates" case.

Why this matters

The current code reads as if it has a sneaky "balancing wins ties" rule. Three concerns:

  1. A reader who doesn't follow the threshold-arithmetic argument (or has the threshold set to 0 for testing) could conclude that ties go to balancing, which isn't justified by the LTM literature.
  2. The inner else branch is logically dead code when used as a tie-breaker, but live code as the "balancing dominates" handler. The same syntactic form serving two semantically-different purposes is a code smell.
  3. If POLARITY_CONFIDENCE_THRESHOLD were ever set to 0 (e.g., a test override), the tie case would hit this branch and silently classify as MostlyBalancing, which is semantically wrong.

Proposed fix

Two options; option 1 is preferred.

Option 1 (preferred): make the cases explicit

(true, true) => {
    if confidence < POLARITY_CONFIDENCE_THRESHOLD {
        LoopPolarity::Undetermined
    } else if positive_sum > negative_sum_abs {
        LoopPolarity::MostlyReinforcing
    } else if negative_sum_abs > positive_sum {
        LoopPolarity::MostlyBalancing
    } else {
        // confidence >= threshold AND positive_sum == negative_sum_abs
        // implies ratio == 0 implies confidence == 0, contradicting
        // the threshold check above (assuming threshold > 0).
        debug_assert!(POLARITY_CONFIDENCE_THRESHOLD > 0.0,
            "tie-case with threshold == 0 would silently classify as Balancing; \
             update the classification rules if you set the threshold to 0");
        LoopPolarity::Undetermined  // safe fallback
    }
}

This makes the invariant testable and the failure mode (threshold = 0 for testing) safe.

Option 2 (less preferred): document the implicit tie-break

// Tie-break: when positive and negative magnitudes are exactly equal
// and confidence is above threshold (which can only happen if the
// threshold is 0), we conventionally classify as balancing.

This is less preferred because "balancing wins ties" is not a documented behavior of the LTM method, and the unreachable-when-threshold > 0 argument deserves a structurally enforced encoding rather than a comment.

Severity

low (code clarity / robustness; no observable correctness change with the current threshold value of 0.99)

File references

  • Code: src/simlin-engine/src/ltm/types.rs:203-258 (LoopPolarity::from_runtime_scores)
  • Threshold definition: src/simlin-engine/src/ltm/types.rs:159-176 (POLARITY_CONFIDENCE_THRESHOLD)

Context

Identified during a code-quality review of the Rux/Bux classification logic landed in PR #490 (tracked under #485 / tech-debt #30). The capability itself is correct; this is purely about how the (true, true) arm reads.

References

Labels

ltm (the code-quality label does not exist in this repo)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ltmLoops that Matter (LTM) analysis subsystem

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions