While porting TBD to Python, three bugs were found in the pyOSut dependency
(osut 0.9.0, https://github.com/rd2/pyOSut). Each deviates from the canonical
Ruby osut behaviour that py-tbd must mirror, so all three are worked around by a
version/behaviour-guarded runtime shim (src/tbd/_compat.py) that no-ops once the
dependency ships a fix. They should be reported/fixed upstream in rd2/pyOSut.
See UPSTREAM.md → Dependency bugs for the authoritative record.
D1 — insulatingLayer raises NameError on massless layers 🔴
osut.py:579, massless branch:
res["r"] = m.thermalResistance() # `m` is undefined; loop var is `l`
Any construction whose insulating layer is a MasslessOpaqueMaterial (very common)
raises NameError: name 'm' is not defined. Fix: m → l.
D2 — insulatingLayer uses hardcoded thresholds instead of RMIN/DMIN/KMAX 🔴
osut.py qualifies a layer with 0.001 / 0.003 / 3.0 where Ruby osut uses
the constants RMIN (0.005), DMIN (0.01), KMAX (2.0). Consequence: a different
layer is selected as "insulating" than in the Ruby gem — e.g. a ~0.15 m
normalweight-concrete floor (k≈2.31) is excluded by Ruby (k > KMAX) but kept
by pyOSut (k > 3.0), changing every downstream derating result for that surface.
Fix: use the RMIN/DMIN/KMAX constants.
D3 — rsi accumulates an Optional instead of a resistance 🔴
osut.py:536, massless branch:
rsi += m.to_MasslessOpaqueMaterial() # missing .get().thermalResistance()
rsi raises TypeError: unsupported operand type(s) for +=: 'float' and 'OptionalMasslessOpaqueMaterial' for any construction containing a massless layer.
Fix: rsi += m.to_MasslessOpaqueMaterial().get().thermalResistance().
Workaround in py-tbd: src/tbd/_compat.py installs _insulating_layer_fixed
(D1+D2) and _rsi_fixed (D3), matching Ruby osut 0.9.1, only when the buggy
behaviour is detected. This issue tracks removing the shim once pyOSut releases a
fix and py-tbd's dependency pin is bumped.
While porting TBD to Python, three bugs were found in the pyOSut dependency
(
osut0.9.0, https://github.com/rd2/pyOSut). Each deviates from the canonicalRuby
osutbehaviour that py-tbd must mirror, so all three are worked around by aversion/behaviour-guarded runtime shim (
src/tbd/_compat.py) that no-ops once thedependency ships a fix. They should be reported/fixed upstream in
rd2/pyOSut.See
UPSTREAM.md→ Dependency bugs for the authoritative record.D1 —
insulatingLayerraisesNameErroron massless layers 🔴osut.py:579, massless branch:Any construction whose insulating layer is a
MasslessOpaqueMaterial(very common)raises
NameError: name 'm' is not defined. Fix:m→l.D2 —
insulatingLayeruses hardcoded thresholds instead of RMIN/DMIN/KMAX 🔴osut.pyqualifies a layer with0.001/0.003/3.0where Rubyosutusesthe constants
RMIN(0.005),DMIN(0.01),KMAX(2.0). Consequence: a differentlayer is selected as "insulating" than in the Ruby gem — e.g. a ~0.15 m
normalweight-concrete floor (k≈2.31) is excluded by Ruby (
k > KMAX) but keptby pyOSut (
k > 3.0), changing every downstream derating result for that surface.Fix: use the
RMIN/DMIN/KMAXconstants.D3 —
rsiaccumulates an Optional instead of a resistance 🔴osut.py:536, massless branch:rsiraisesTypeError: unsupported operand type(s) for +=: 'float' and 'OptionalMasslessOpaqueMaterial'for any construction containing a massless layer.Fix:
rsi += m.to_MasslessOpaqueMaterial().get().thermalResistance().Workaround in py-tbd:
src/tbd/_compat.pyinstalls_insulating_layer_fixed(D1+D2) and
_rsi_fixed(D3), matching Ruby osut 0.9.1, only when the buggybehaviour is detected. This issue tracks removing the shim once pyOSut releases a
fix and py-tbd's dependency pin is bumped.