You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Status: Verified bug against the current master source in this fork.
Severity: High.
Area labels: area:containers.
Tackle batch: P3 - documented-mode crashes and tooling breakages.
The source review confirmed that the cited code path and failure mode are still present. The original audit details are preserved below for reproduction notes and suggested fixes.
Original audit details
Severity: High · Part of #67 (round-2 audit batch)
Cake branch leaves self.Outlet and distrib unbound, then unconditionally calls energy_balance and returns distrib
The slurry-vs-cake split at line 476 (if vol_liq > vol_pores) only fully populates the Slurry branch (476-499 sets self.Outlet at 482/497, self.Outlet.Phases at 499, and local distrib at 479). The else/Cake branch (500-502) is a stub: self.type_out = 'Cake' then 'pass # TODO: create Cake object' -- it never assigns self.Outlet or distrib. Execution unconditionally reaches line 505 temp_out = self.energy_balance(u_inputs), and energy_balance (360-361) calls self.Outlet.getEnthalpy(temp) inside temp_root via newton -> AttributeError ('Mixer' has no attribute 'Outlet'; Mixer.init never sets it). Even if bypassed, line 507 returns the unbound local distrib -> UnboundLocalError. retrieve_results (582-585) explicitly branches on type_out=='Cake' and line 595 calls self.Outlet.Solid_1.updatePhase(...), confirming Cake is an intended mode.
Trigger: A Mixer fed at least one MixedPhases (Slurry/Cake) inlet plus enough solid / little enough liquid that vol_liq <= vol_pores (the physically correct wet-cake outcome). solve_unit -> balances_solids takes the else branch at line 500. balances_solids runs when an inlet is MixedPhases and mass_frac is not a list (the non-timeseries batch path).
Wrong result: AttributeError (self.Outlet has no getEnthalpy) at line 505 via energy_balance, or UnboundLocalError on distrib at line 507. The mixer is unrunnable for any solids mix that yields a cake, despite retrieve_results being written to handle type_out=='Cake'.
Suggested fix: Implement the Cake branch: build a Cake/Outlet object and assign distrib before line 505 (e.g. distrib = distrib_in.sum(axis=0) and self.Outlet = Cake with the liquid/solid phases). If cake output is not yet supported, raise an explicit NotImplementedError in the else branch instead of 'pass', and guard energy_balance/the return so they are not reached with an unset Outlet.
Related existing issues (referenced, not modified):#25 (Mixer slurry liquid-only mass weighting), #38 (Mixer reference-temperature mismatch), #75 (DynamicCollector) -- reference only; none cover the Cake-branch crash.
Found by a multi-agent source audit (round 2); confirmed by re-reading the source and cross-checked against all 80 existing open issues. Each defect was verified by an independent code-truth skeptic and a novelty skeptic.
Maintainer triage (June 29, 2026)
mastersource in this fork.The source review confirmed that the cited code path and failure mode are still present. The original audit details are preserved below for reproduction notes and suggested fixes.
Original audit details
Severity: High · Part of #67 (round-2 audit batch)
Cake branch leaves self.Outlet and distrib unbound, then unconditionally calls energy_balance and returns distrib
Location:
PharmaPy/Containers.py:500-507 (also 505, 580, 595)The slurry-vs-cake split at line 476 (if vol_liq > vol_pores) only fully populates the Slurry branch (476-499 sets self.Outlet at 482/497, self.Outlet.Phases at 499, and local distrib at 479). The else/Cake branch (500-502) is a stub: self.type_out = 'Cake' then 'pass # TODO: create Cake object' -- it never assigns self.Outlet or distrib. Execution unconditionally reaches line 505 temp_out = self.energy_balance(u_inputs), and energy_balance (360-361) calls self.Outlet.getEnthalpy(temp) inside temp_root via newton -> AttributeError ('Mixer' has no attribute 'Outlet'; Mixer.init never sets it). Even if bypassed, line 507 returns the unbound local distrib -> UnboundLocalError. retrieve_results (582-585) explicitly branches on type_out=='Cake' and line 595 calls self.Outlet.Solid_1.updatePhase(...), confirming Cake is an intended mode.
Related existing issues (referenced, not modified): #25 (Mixer slurry liquid-only mass weighting), #38 (Mixer reference-temperature mismatch), #75 (DynamicCollector) -- reference only; none cover the Cake-branch crash.
Found by a multi-agent source audit (round 2); confirmed by re-reading the source and cross-checked against all 80 existing open issues. Each defect was verified by an independent code-truth skeptic and a novelty skeptic.