Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Notation, all in feet: the battery stands at s from `s0` to `s1` (width W = 2.58
| `route_path` | `walls`, openings on the route | wall band from the meter to the battery's near edge, seen higher than the cable's run (`route.height_ft`, 1.0) |
| `route_length` | `walls`, `meter` | nothing to observe |

Errors: a measured value passes only when it clears the rule by more than its error. Objects take the default error for their `source` (tape 0.05, tap 0.3, vlm 1.5, plus 0.16 per foot along the walls for tap and vlm) unless they carry `plus_minus_ft`, and walls likewise (tap 0.3, mesh 0.5, plane 0.75, each plus the same drift). Send a wall's `source` when its line comes from the mesh or detected planes rather than taps, so the error bars match how it was measured; `facing` and `overheads` entries default to the mesh error, 0.5. Every `out_ft` is taken as exact, so report the distance you are sure of (for a walked path, the distance from the wall less your position error).
Errors: a measured value passes only when it clears the rule by more than its error. Objects take the default error for their `source` (tape 0.05, tap 0.3, vlm 1.5, plus 0.16 per foot along the walls for tap and vlm) unless they carry `plus_minus_ft`, and walls likewise (tap 0.3, mesh 0.5, plane 0.75, each plus the same drift). Send a wall's `source` when its line comes from the mesh or detected planes rather than taps, so the error bars match how it was measured; `facing` and `overheads` entries default to the mesh error, 0.5. The meter's working space passes only when the battery is clear of it by more than the meter's error plus e, but fails as soon as the battery overlaps it by more than e alone: the spot is placed and shown against the meter's anchor, so the meter's error can hold back a pass but never excuse an overlap (issue #44). Every `out_ft` is taken as exact, so report the distance you are sure of (for a walked path, the distance from the wall less your position error).

Ends and corners:

Expand Down
6 changes: 5 additions & 1 deletion server/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,8 +591,12 @@ def check_meter_space(self, piece: Piece, fp: Polygon, s0: float, s1: float) ->
if d <= EPS:
d = min(0.0, max(self.ws_span[0] - s1, s0 - self.ws_span[1]))
e = self.scene.meter_plus_minus + piece.plus_minus
c.measured, c.plus_minus = d, e
c.outcome = at_least(d, e, 0.0)
# The spot is placed and shown against the meter's anchor, so the meter's error can hold
# back a pass but never excuse an overlap the wall's error alone doesn't cover.
if c.outcome == UNSURE and at_least(d, piece.plus_minus, 0.0) == FAIL:
c.outcome, e = FAIL, piece.plus_minus
c.measured, c.plus_minus = d, e
box = f"{ft(ws.width_ft.value)} wide by {ft(ws.depth_ft.value)} deep"
if c.outcome == FAIL:
c.reason = f"The battery would stand in the {box} working space in front of the meter."
Expand Down
28 changes: 26 additions & 2 deletions server/tests/test_field_run_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import copy

from helpers import observed_band, parsed, rect, shared_fixture
import pytest
from helpers import W, at_start, observed_band, parsed, rect, shared_fixture
from hypothesis import given, settings
from hypothesis import strategies as st
from test_s4_round import PUBLIC, answer

from solver import SOLVE_BUDGET_S, UNSURE, Solver, estimate_fails
from solver import FAIL, PASS, SOLVE_BUDGET_S, UNSURE, Solver, estimate_fails

# --- #44: a spot whose best estimate overlaps the meter's working space ----------------------

Expand Down Expand Up @@ -57,6 +58,29 @@ def test_an_estimate_past_a_rule_never_outranks_one_that_clears(
assert not estimate_fails(chosen)


def test_an_overlap_past_the_walls_error_fails_the_working_space() -> None:
# Before: -1.25 against the meter's 0.792 plus the wall's 0.713 was UNSURE. The meter's
# error no longer excuses an overlap, so the numbers give FAIL: -1.25 + 0.713 < 0.
c = at_start(meter_known_loosely(), -W, "meter_working_space", PUBLIC)
assert c.measured == pytest.approx(-1.25)
assert c.outcome == FAIL
assert c.plus_minus == pytest.approx(0.713)


@pytest.mark.parametrize(
("s1", "outcome"),
[
(-1.25 - 0.792 - 0.713 - 0.1, PASS), # clear by more than both errors
(-1.25 - 0.1, UNSURE), # clear, but by less than both
(-1.25 + 0.713 - 0.1, UNSURE), # an overlap within the wall's error
],
)
def test_the_meters_error_still_holds_back_a_working_space_pass(s1: float, outcome: str) -> None:
c = at_start(meter_known_loosely(), s1 - W, "meter_working_space", PUBLIC)
assert c.outcome == outcome
assert c.plus_minus == pytest.approx(0.792 + 0.713)


# --- #45: the summary counts only unseen checks -----------------------------------------------


Expand Down