# -*- coding: utf-8 -*- """The gate's opening deduction prefers the MEASURED removed volume. Every blockout/recess entry in the job file now carries `removed_ft3` -- the concrete volume actually removed inside that opening's footprint, measured by an in-memory boolean -- or `None` when it could not be measured. Before this, `weight_check` deducted blockouts at full thickness and recesses by `depth_in` (a centre-line probe), which reads a sloped/stepped/far-face recess as 0 and refused the piece. `_opening_deduction_ft3` is the pure half of that fix: the measured volume wins when it is a number, and the geometric fallback (full thickness through a blockout, `depth_in` for a blind recess) stands only where there is no measurement. These pin both branches -- and that `weight_check` still refuses a pocket that was never measured rather than blessing a guess. """ import pytest from vibe import liftexport # ------------------------------------------------------- the pure helper def test_measured_volume_wins_regardless_of_geometry(): blockout = {'length': 4.0, 'width': 5.0, 'removed_ft3': 2.5} recess = {'length': 2.0, 'width': 3.0, 'depth_in': 6.0, 'removed_ft3': 2.5} assert liftexport._opening_deduction_ft3(blockout, 8.0, True) == \ pytest.approx(2.5) assert liftexport._opening_deduction_ft3(recess, 8.0, False) == \ pytest.approx(2.5) def test_an_unmeasured_through_blockout_deducts_full_thickness(): blockout = {'length': 4.0, 'width': 5.0} got = liftexport._opening_deduction_ft3(blockout, 8.0, True) assert got == pytest.approx(4.0 * 5.0 * 8.0 / 12.0) def test_an_unmeasured_recess_deducts_its_own_depth(): recess = {'length': 2.0, 'width': 3.0, 'depth_in': 4.5} got = liftexport._opening_deduction_ft3(recess, 8.0, False) assert got == pytest.approx(2.0 * 3.0 * 4.5 / 12.0) def test_a_recess_with_no_depth_deducts_nothing(): recess = {'length': 2.0, 'width': 3.0} assert liftexport._opening_deduction_ft3(recess, 8.0, False) == 0.0 # --------------------------------------------------- the gate, end to end # # The reconciling 20 x 10 ft x 8 in single-solid piece, with a 2 x 3 ft # recess 6 in deep -- 3.0 ft3, 2.30% of the solid. Mirrors the minimal # `_weight_job` fixture in test_liftexport.py, plus a recess. def _measured_recess_job(removed_ft3, depth_in): gross = 20.0 * 10.0 * 8.0 / 12.0 # 133.3333 ft3 solid = gross - 3.0 # the true pocket is 3.0 ft3 return { 'panel': { 'length_ft': 20.0, 'width_ft': 10.0, 'thickness_in': 8.0, 'unit_weight_pcf': 150.0, 'weight_lb': solid * 150.0, 'blockouts': [], 'recesses': [{'name': 'RECESS 1', 'x0': 1.0, 'y0': 1.0, 'length': 2.0, 'width': 3.0, 'depth_in': depth_in, 'removed_ft3': removed_ft3}], 'extra_cast_ft3': 0.0, }, 'source': {'solid_ft3': solid, 'solid_basis': 'material density', 'solid_note': 'the body draws one solid'}, } def test_a_measured_recess_reconciles_and_the_gate_passes(): ok, message, numbers = liftexport.weight_check( _measured_recess_job(removed_ft3=3.0, depth_in=6.0)) assert ok and message == '' assert numbers['reconstructed_lb'] == pytest.approx( numbers['solid_lb'], rel=1e-9) def test_an_unmeasured_shallow_recess_is_still_refused(): """`removed_ft3=None` with `depth_in=0` leaves the 3.0 ft3 pocket in, so the reconstruction reads 2.30% heavier than the piece's own solid and the gate refuses rather than blessing a guess.""" ok, message, numbers = liftexport.weight_check( _measured_recess_job(removed_ft3=None, depth_in=0.0)) assert not ok assert 'we did not take out' in message assert numbers['reconstructed_lb'] > numbers['solid_lb']