fix(aap): Correct an overstated safety claim and a test that proved nothing

Review follow-ups on the previous commit.

Its claim that "nothing is learned or persisted" was wrong. BatteryEstimator
buckets drain samples by the current listening mode and force-persists the
accumulated window whenever that mode changes, so a misattributed mode can write
a drain rate to disk under the wrong bucket, and the corrective report does not
remove it. This is not new: the misreport being fixed here already mis-buckets in
the same way, and more often, since the device claims OFF while the pods play
Adaptive. Classifying corrects the common case and only gets it wrong on the rarer
misattribution. The design stands, the claim does not.

Two other claims were also too strong. The recorded echo is the first report after
the verification was installed, which is not exactly the wire write, so write
contention above the latency boundary can still inflate a fast refusal. And a
superseded write is not left alone entirely: classification is skipped, but it
still falls through to the ordinary retry path.

The supersession regression test asserted nothing: it fed a fresh ADAPTIVE report
in before its only assertion, overwriting either outcome, so it passed whether or
not the guard existed. It now asserts on the state left by the delayed echo, and
fails with the guard removed.

Also drops an unused import and restores an indent lost when the remap argument
was removed.
This commit is contained in:
darken
2026-08-20 00:06:03 +02:00
parent b396ce457d
commit 0b83e86c5e
2 changed files with 4 additions and 12 deletions
@@ -361,7 +361,7 @@ internal class AapSessionEngine(
EngineTimerKey.Verification -> {
applyOutboundDecisionAsync(
outboundController.onVerificationTimerFired(_state.value, runtimeState.outbound),
outboundController.onVerificationTimerFired(_state.value, runtimeState.outbound),
)
}
}
@@ -14,7 +14,6 @@ import io.kotest.matchers.collections.shouldBeEmpty
import io.kotest.matchers.nulls.shouldBeNull
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.flow.first
@@ -882,16 +881,9 @@ class AapSessionEngineTest : BaseTest() {
engine.processMessage(dummyMessage())
advanceTimeBy(AapOutboundController.VERIFICATION_TIMEOUT_MS * 2 + 100L)
// Must not have learned ADAPTIVE -> TRANSPARENCY. A later genuine ADAPTIVE report
// therefore still reads as ADAPTIVE.
nextSetting = settingPair(
AapSetting.AncMode(
current = AapSetting.AncMode.Value.ADAPTIVE,
supported = supportedModes,
)
)
engine.processMessage(dummyMessage())
advanceTimeBy(1600L)
// Without supersession the classifier would call this ADAPTIVE report the answer to
// the TRANSPARENCY write and force TRANSPARENCY into state. State must instead stay
// on what the device actually reported.
engine.state.value.setting<AapSetting.AncMode>()!!.current shouldBe
AapSetting.AncMode.Value.ADAPTIVE
}