Skip to content

fix(recovery): align trace half-tie rounding - #1437

Merged
ryanbr merged 1 commit into
ryanbr:mainfrom
bhelm:fix/recovery-trace-half-ties
Aug 19, 2026
Merged

ryanbr merged 1 commit into
ryanbr:mainfrom
bhelm:fix/recovery-trace-half-ties

Conversation

@bhelm

@bhelm bhelm commented Aug 18, 2026

Copy link
Copy Markdown

What this PR does

Aligns Kotlin Recovery diagnostic trace rounding with Swift for positive and negative half-ties by using an explicit nearest, ties-away-from-zero rule.

The Recovery score is unchanged; only trace formatting is affected. Mirrored tests also pin ordinary non-ties and score neutrality.

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Documentation
  • CI / tooling

How it was tested

  • cd Packages/StrandAnalytics && swift test --filter RecoveryScorerTraceTests — 6 tests passed
  • cd android && ./gradlew :app:testFullDebugUnitTest --tests "com.noop.analytics.RecoveryScorerTraceTest" --no-daemon --max-workers=1 --no-parallel — 6 tests passed

Only the focused suites were run. No manual, device, or strap testing was performed; this is pure diagnostic formatting.

Checklist

  • Swift package tests pass for any package I touched — focused suite passed; full package suite was not run
  • Android unit tests pass if I touched android/ — focused suite passed; full suite was not run
  • No new build warnings introduced
  • UI changes use only StrandDesign tokens — not applicable
  • No hardcoded protocol bytes — not applicable
  • Follows docs/CONTRIBUTING.md
  • No generated output or secrets committed

Related issues

Related: bhelm#38
Follow-up rounding bounds: bhelm#47

@ryanbr
ryanbr merged commit 13d4134 into ryanbr:main Aug 19, 2026
14 checks passed
ryanbr added a commit that referenced this pull request Aug 19, 2026
… skin-temp comment

Two residuals left behind by the rounding/formatting parity work in @bhelm's #1437 and #1440,
found by re-checking those merges rather than by a report.

#1437 aligned the half-tie rule but left the near-zero case divergent, and the helper turned out to
hold TWO traps for a negative zero. Math.round returns a Long, which has no negative zero, so negating
it before the division collapses -0.0 to +0.0 for anything that rounds to zero; and `-0.0 < 0.0` is
FALSE, so a sign comparison cannot route an exact -0.0 into a negating branch at all. The second is
reachable, not hypothetical: the skin-temp term is z = -|dev| / scale, so a deviation of exactly 0.0
produces -0.0. These values are interpolated straight into the trace, so either trap printed z=0.0 on
Android against z=-0.0 on Apple. Rounding the magnitude and reapplying the sign with copySign handles
both; verified on a JVM across -0.0, small negatives, half-ties in both directions and positives.

#1440's comment described a bug that does not exist. `%+.1f` renders -0.0 as "-0.0" and 0.0 as
"+0.0" on both C printf and Java's Formatter, checked directly. The real defect it fixed was the sign
built from `dev >= 0`, which is TRUE for -0.0, prepending "+" to a value already formatting as
"-0.0" and printing "+-0.0". The comment now states only what was checked, and gives the honest
reason the explicit branch stays: it pins the edge so the two zeroes cannot drift from the twin on a
Foundation whose formatter has not been tested.

Two mirrored vectors per platform cover the near-zero and the exact -0.0 case. Android 4,067 tests /
0 failures; both files sit under Packages, so swift-packages executes the Swift twin.
@bhelm
bhelm deleted the fix/recovery-trace-half-ties branch September 15, 2026 22:35
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