Skip to content

test(codegen): the sweep sees a divisor scaled from the guarded value (#390) - #392

Merged
mario4tier merged 1 commit into
TA-Lib:devfrom
kevinlincg:issue-390-scaled-divisor
Sep 6, 2026
Merged

test(codegen): the sweep sees a divisor scaled from the guarded value (#390)#392
mario4tier merged 1 commit into
TA-Lib:devfrom
kevinlincg:issue-390-scaled-divisor

Conversation

@kevinlincg

Copy link
Copy Markdown
Collaborator

#390 found a defect that divisor_guard_suite should have caught and did not. This
closes that gap in the sweep; it does not change STOCH or STOCHF.

Why the sweep was blind to it

The suite had one shape: a divisor accumulated across loop iterations with no guard
testing it. STOCH's diff is a fresh assignment, so it never entered the accumulator
set and the sweep read clean — on a defect of exactly the class the suite exists for.

The shape it missed is a different one, and #390 states it exactly: the guard tests one
expression and the code divides by another. stoch.c:230 guards highest - lowest,
:231 divides by diff, and :189 sets diff = (highest - lowest)/100.0. A denormal
range leaves the guarded expression non-zero while the divisor underflows to exactly
0.0, so the guard proves something true about a number that is not the divisor.

The second arm

A divisor assigned inside a loop from an expression that multiplies or divides is
recorded together with the variables that expression reads. If no guard tests the
divisor, but some dominating guard tests one of those reads, that is a finding.

Addition and subtraction are deliberately excluded: they cannot send a
guarded-non-zero to a zero divisor the way a scaling can, and including them would bury
the real rows.

Over 202 input functions it flags STOCH and STOCHF, and nothing else — the two
#390 names.

Pinned in the direction the existing self-tests do not cover

The ER and VORTEX self-tests prove the sweep goes loud on a reintroduced defect. A
check that flagged every scaled divisor unconditionally would pass both of those and
still be worthless, so this arm is pinned the other way:
the_scaled_arm_clears_when_the_guard_moves_to_the_divisor rewrites STOCH's guard onto
diff — the fix #390 suggests — and requires the finding to disappear. It fails if the
check is not actually reading the guard.

STOCH/STOCHF are annotated OPEN, not patched

Moving the guard onto diff changes STOCH's output on those windows, so it is a
decision about a shipped function rather than something to slip in under a sweep — the
same line drawn for KAMA in #383 and settled by ruling in #385. #390 also notes the
frozen pre-cutover reference shares the defect, so the corrected values need Tulip or
pandas-ta as an oracle; that is not something a test suite can decide.

no_annotation_is_stale already covers the follow-through: whenever the guard does
move, these two rows stop being flagged and the suite says so rather than leaving a row
asserting a closed question.

Not covered, stated rather than implied

#390's second half — KAMA's quotient overflowing when sumROC1 is tiny-but-non-zero
and periodROC is large — is not detected by this change. It is not a missing
denominator test at all: #385 added the exact zero guard and it holds. The defect is an
unbounded quotient, which needs a check about the result rather than about the divisor,
and I did not want to claim coverage the suite does not have.

Verification

cargo clippy --all-targets clean, 936 generator tests green, ta_regtest green. One
file changed; no generated source touched.

…TA-Lib#390)

TA-Lib#390 reports STOCH/STOCHF returning TA_SUCCESS with inf/nan for
well-formed OHLC: stoch.c:230 guards `highest - lowest` and :231 divides
by `diff`, which :189 sets to `(highest - lowest)/100.0`. A denormal
range leaves the guarded expression non-zero while the divisor underflows
to exactly 0.0.

divisor_guard_suite did not see it, and could not: its one shape is a
divisor accumulated across loop iterations, and `diff` is a fresh
assignment. So the sweep read clean on a defect of exactly the class it
exists for.

Adds a second shape. A divisor assigned from an expression that
MULTIPLIES OR DIVIDES is recorded with the variables that expression
reads; if no guard tests the divisor but some guard tests one of those
reads, that is reported. Addition and subtraction are excluded -- they
cannot turn a guarded-non-zero into a zero divisor the way a scaling can.

It flags STOCH and STOCHF, and nothing else in 202 functions. Both are
annotated OPEN rather than patched: moving the guard onto `diff` changes
their output on those windows, which is a decision about the functions.

The new arm is pinned in the direction the existing self-tests do not
cover. ER and VORTEX prove the sweep goes loud on a reintroduced defect;
this one moves STOCH's guard onto `diff` and requires the finding to
disappear, so a check that flagged every scaled divisor unconditionally
would fail it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants