Changes in version 1.3.0 (2026-10-04) - Fixed: open_nl() passed loss and freq to the maximum power output calculation by position, so they landed in unused arguments and the MPO never included the conductive component of a mixed or conductive loss. Results for purely sensorineural losses are unchanged. - Fixed: open_nl() called without loss returned its starting rule-based gains without optimizing. The missing loss was passed to sii() inside the objective function, where it caused an error that was caught and scored as a constant, so Nelder-Mead never moved. A missing loss is now treated as no conductive loss. Calls that supplied loss were not affected. - The Johnson & Dillon (2011) desensitization option is now named "johnson2011_desensitized" in sii() and open_nl(). The old name "johnson2011_complete" still works but gives a deprecation warning. - Loudness is now computed by calculate_loudness_audmod(), a C++ port of the AUDMOD model (Bramslow, 2004) that matches the Auditory Modeling Toolbox (AMT 1.6.0) bramslow2004 implementation at every stage. Tests compare it against AMT reference output for 23 cases. - open_nl() gains objective_sii, which selects the SII the optimizer maximizes. The default is "johnson2011_desensitized", the Johnson & Dillon (2011) desensitization correction; "none" optimizes the ANSI S3.5 SII. - Removed the desensitization_scale argument from sii() and open_nl(). Desensitization is now either off ("none", ANSI S3.5 SII) or the full Johnson & Dillon (2011) correction ("johnson2011_desensitized"); there is no partial blend. Passing desensitization_scale is an error. - Removed the "johnson2011_smoothed" desensitization option (a product-form approximation, K * m) from sii() and open_nl(). The complete correction optimizes without difficulty, so the approximation is no longer needed. sii() now stops with an error for an unrecognized desensitization value instead of silently computing the ANSI SII. - open_nl() now optimizes a negative vent_floor once, at the floor requested. Previously it also optimized with the floor at 0 dB and returned whichever solution had the higher raw SII, so the requested floor was not always honored and differences between floors could never be negative. - sii() no longer floors a prescription_target's insertion gain at 0 dB after output limiting. Negative insertion gain now lowers the speech level in the SII calculation, as it does in the loudness model; previously a gain cut below 0 dB was invisible to the SII. - Changed open_nl() default loudness cap to a normal-loudness cap. The new cap uses normal_speech_loudness() to dynamically compute the normal-hearing loudness of unaided speech at the evaluation level. The legacy behavior (PTA-based knots, reverse-slope penalty, and ABG adjustments) is still available via cap_rule = "legacy".