Files
willtools-demo/WillTools.extension/tests/test_reinforcebind.py
T
will 52d94303bc
ci / test (push) Has been cancelled
WillTools: precast shop-ticket QC and panel handling tools
Public demo snapshot of an in-house pyRevit extension for precast concrete
shop-ticket QC (37 checks / 46 checklist rows) and a standalone panel
handling solver (PCI Chapter 8).

- No client, job, plant or product data: knowledge layers ship as
  structural templates only.
- Ticket QC's model-read escalation targets a LAN model server endpoint
  (configurable), not a cloud provider.
- Built from the private development repo via tools/make_dist.py.
2026-09-03 16:33:47 -05:00

1375 lines
62 KiB
Python

# -*- coding: utf-8 -*-
"""The binding: ligament features, the production `covers`, the donor filter.
Every piece here is invented and every mark is a `PNL...` placeholder, which
is this project's convention -- no real panel mark, job or client name appears
in this file. The worked-example shapes are rebuilt with invented marks
because the geometry is what the tests are about, not the job.
"""
# pylint: disable=import-error,invalid-name
import os
import pytest
from vibe import reinforcecore as core
from vibe import reinforcebind as B
from vibe import reinforcematch as match
# ---------------------------------------------------------------- fixtures
# The design number every fixture carries unless a test says otherwise.
#
# It is SHARED on purpose. A donor must be the same design as its target
# (owner ruling, 2026-09-01, enforced in `DonorFilter`), so a fixture set
# where every piece had its own design number would be a fixture set where
# nothing can ever donate to anything -- and every test about geometry,
# ranking, MASTER or the cap would be testing the design filter instead of
# what it says on its name. Tests that are about the design rule pass `design`
# explicitly; everything else stays inside one design and reads as before.
DESIGN = 'PNL1.0'
def piece(name, length, width, thickness, rects, reinforced=1, on_hold=0,
master=False, design=DESIGN, elevation_band=None,
elevation_group=None):
"""An index piece record. `rects` are (x0, x1, y0, y1[, through]).
`elevation_band` is a `{'axis': ..., 'min': ..., 'max': ...}` dict (or
None) -- the geometric FLOOR (owner's 2026-09-02 ruling). `band(...)`
below is the convenience most tests actually want. `elevation_group` is
the optional ACCELERATOR -- an opaque plant-declared string (MC's is
`Tagged_Sheet`) -- present on neither fixture unless a test says so,
which mirrors most real jobs.
"""
feats = []
for i, r in enumerate(rects):
through = r[4] if len(r) > 4 else True
feats.append(core.feature(name, i, r[0], r[1], r[2], r[3],
through, 0.0 if through else 3.5,
length, width, thickness))
return core.piece_record(name, 1, 'sig', reinforced, on_hold,
design_number=design,
length_ft=length, width_ft=width,
thickness_in=thickness, features=feats,
master=master,
master_note='MASTER' if master else None,
elevation_band=elevation_band,
elevation_group=elevation_group)
def band(tag, axis='X'):
"""A distinct elevation band for a fixture, keyed by a short tag.
Not a real coordinate -- these tests are about the RANKING and the
AFFINITY logic, not about `elevation_band()`'s own geometry (that is
`test_reinforcecore.py`'s job). Each distinct `tag` gets its own
100 ft-wide slot on `axis` so two different tags never accidentally
overlap, and the same `tag` always returns the identical band, so two
fixtures built with `band('ELEV-3')` genuinely share one elevation.
"""
if tag is None:
return None
# A plain character-code sum, not `hash()` -- Python randomises string
# hashing per process, and this has to return the SAME band for the
# SAME tag every time it is called, not just within one run.
slot = sum(ord(c) for c in (axis + str(tag))) % 1000
lo = float(slot) * 100.0
return {'axis': axis, 'min': lo, 'max': lo + 0.667}
def kinds(feats):
out = {}
for f in feats:
out[f['kind']] = out.get(f['kind'], 0) + 1
return out
def find(feats, kind, x0, x1, y0, y1):
for f in feats:
if (f['kind'] == kind and abs(f['x0'] - x0) < 1e-6 and
abs(f['x1'] - x1) < 1e-6 and abs(f['y0'] - y0) < 1e-6 and
abs(f['y1'] - y1) < 1e-6):
return f
return None
# ------------------------------------------------- what a ligament is
def test_two_openings_leave_the_strip_between_them():
"""The reframe, in one test: the concrete between the holes is a feature
belonging to neither hole."""
p = piece('PNL601', 20.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (9.0, 11.0, 2.0, 5.0)])
feats = B.features_for(p)
strip = find(feats, B.STRIP_X, 6.0, 9.0, 2.0, 5.0)
assert strip is not None
assert strip['strip_ft'] == 3.0 # the gap between them
assert strip['span_ft'] == 3.0 # how far it runs across
assert strip['between'] == B.VOID_VOID
def test_identical_holes_different_spacing_are_different_features():
"""Same two holes, moved apart. The holes are identical; the strip is not.
This is the whole point of the reframe."""
near = B.features_for(piece('PNL602', 20.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (6.5, 8.5, 2.0, 5.0)]))
far = B.features_for(piece('PNL603', 20.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (9.0, 11.0, 2.0, 5.0)]))
assert find(near, B.STRIP_X, 6.0, 6.5, 2.0, 5.0)['strip_ft'] == 0.5
assert find(far, B.STRIP_X, 6.0, 9.0, 2.0, 5.0)['strip_ft'] == 3.0
def test_ligament_runs_to_the_panel_edge():
p = piece('PNL604', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
feats = B.features_for(p)
left = find(feats, B.STRIP_X, 0.0, 4.0, 2.0, 5.0)
right = find(feats, B.STRIP_X, 6.0, 20.0, 2.0, 5.0)
below = find(feats, B.STRIP_Y, 4.0, 6.0, 0.0, 2.0)
above = find(feats, B.STRIP_Y, 4.0, 6.0, 5.0, 10.0)
for f in (left, right, below, above):
assert f is not None
assert f['between'] == B.VOID_EDGE
assert left['edge'] == 'x0' and right['edge'] == 'x1'
assert below['edge'] == 'y0' and above['edge'] == 'y1'
def test_a_void_flush_with_the_edge_leaves_no_ligament_there():
"""No concrete, no feature. The flush condition shows up as the ABSENCE
of the strip, which the set cover reads correctly."""
p = piece('PNL605', 20.0, 10.0, 8.0, [(0.0, 2.0, 2.0, 5.0)])
feats = B.features_for(p)
assert not [f for f in feats if f['edge'] == 'x0']
assert [f for f in feats if f['edge'] == 'x1']
def test_no_ligament_is_claimed_through_a_third_void():
"""A strip must be concrete you can point at. Two voids far apart with a
third between them do not leave a strip spanning the lot."""
p = piece('PNL606', 30.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (12.0, 14.0, 2.0, 5.0),
(20.0, 22.0, 2.0, 5.0)])
feats = B.features_for(p)
assert find(feats, B.STRIP_X, 6.0, 20.0, 2.0, 5.0) is None # through v1
assert find(feats, B.STRIP_X, 6.0, 12.0, 2.0, 5.0) is not None
assert find(feats, B.STRIP_X, 14.0, 20.0, 2.0, 5.0) is not None
def test_voids_in_different_height_bands_leave_no_strip_between_them():
"""Requirement 6, at the construction end: an x-gap is only a strip if the
two voids actually overlap in y."""
p = piece('PNL607', 20.0, 12.0, 8.0,
[(4.0, 6.0, 1.0, 3.0), (9.0, 11.0, 8.0, 10.0)])
feats = B.features_for(p)
assert not [f for f in feats if f['between'] == B.VOID_VOID]
def test_never_measured_stays_never_measured():
"""`features is None` must not become an empty list on the way through."""
p = core.piece_record('PNL608', 1, 'sig', 1, 0, error='solid failed')
assert B.features_for(p) is None
def test_measured_and_empty_is_a_list_not_none():
p = piece('PNL609', 20.0, 10.0, 8.0, [])
assert B.features_for(p) == []
def test_include_voids_off_leaves_only_ligaments():
p = piece('PNL610', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
assert kinds(B.features_for(p, include_voids=False)).get(B.OPENING) is None
assert kinds(B.features_for(p)).get(B.OPENING) == 1
# ------------------------------------------------------- the covers contract
def test_identical_features_are_exact():
a = piece('PNL611', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
b = piece('PNL612', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
fa, fb = B.features_for(a), B.features_for(b)
for i in range(len(fa)):
assert B.covers(fa[i], fb[i]) == 0.0
def test_covers_never_raises_on_junk():
"""Requirement 1: total. Anything unjudgeable is None, not an exception."""
good = B.features_for(piece('PNL613', 20.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0)]))[0]
for junk in (None, {}, {'kind': B.OPENING}, 'nonsense', 42, [],
{'kind': B.OPENING, 'x0': 'a', 'x1': 1, 'y0': 0, 'y1': 1}):
assert B.covers(junk, good) is None
assert B.covers(good, junk) is None
def test_covers_is_deterministic():
a = B.features_for(piece('PNL614', 20.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0)]))[0]
b = B.features_for(piece('PNL615', 20.0, 10.0, 8.0,
[(4.1, 6.1, 2.0, 5.0)]))[0]
assert len(set(B.covers(a, b) for _ in range(20))) == 1
def test_a_strip_never_covers_an_opening():
"""Requirement: kinds do not mix, however well the rectangles line up."""
p = piece('PNL616', 20.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (9.0, 11.0, 2.0, 5.0)])
feats = B.features_for(p)
opening = [f for f in feats if f['kind'] == B.OPENING][0]
strip = find(feats, B.STRIP_X, 6.0, 9.0, 2.0, 5.0)
assert B.covers(strip, opening) is None
assert B.covers(opening, strip) is None
def test_strips_on_the_two_axes_do_not_mix():
x_strip = {'kind': B.STRIP_X, 'x0': 4.0, 'x1': 6.0, 'y0': 2.0, 'y1': 5.0,
'strip_ft': 2.0}
y_strip = {'kind': B.STRIP_Y, 'x0': 4.0, 'x1': 6.0, 'y0': 2.0, 'y1': 5.0,
'strip_ft': 3.0}
assert B.covers(x_strip, y_strip) is None
def test_donor_strip_may_be_narrower_but_never_wider():
"""The directional rule (requirement 3): bars detailed for a narrow strip
fit a wider one; a cage for a wide strip does not fit narrower concrete."""
narrow = {'kind': B.STRIP_X, 'x0': 5.0, 'x1': 6.0, 'y0': 2.0, 'y1': 5.0,
'strip_ft': 1.0}
wide = {'kind': B.STRIP_X, 'x0': 4.5, 'x1': 6.5, 'y0': 2.0, 'y1': 5.0,
'strip_ft': 2.0}
assert B.covers(narrow, wide) is not None # narrow donor -> wide target
assert B.covers(wide, narrow) is None # will not fit
def test_a_feature_in_a_different_height_band_is_not_covered():
"""Requirement 6. The measurement this rule comes from: two features share
an x-range while sitting in different Z bands."""
low = {'kind': B.OPENING, 'x0': 4.0, 'x1': 6.0, 'y0': 1.0, 'y1': 3.0}
high = {'kind': B.OPENING, 'x0': 4.0, 'x1': 6.0, 'y0': 8.0, 'y1': 10.0}
assert B.covers(low, high) is None
def test_position_is_absolute_not_proportional():
"""Requirement 5: the same rectangle on panels of different lengths is the
same feature, and a mid-panel rectangle at the same FRACTION is not."""
short = piece('PNL617', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
long = piece('PNL618', 40.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
scaled = piece('PNL619', 40.0, 10.0, 8.0, [(8.0, 12.0, 2.0, 5.0)])
s = [f for f in B.features_for(short) if f['kind'] == B.OPENING][0]
l = [f for f in B.features_for(long) if f['kind'] == B.OPENING][0]
p = [f for f in B.features_for(scaled) if f['kind'] == B.OPENING][0]
assert B.covers(l, s) == 0.0
assert B.covers(p, s) is None
def test_distance_is_in_inches_and_comparable_across_kinds():
"""Requirement 4: one unit for every kind, and that unit is INCHES.
The records are feet -- 0.5 ft of corner offset -- and `covers` crosses
the unit seam exactly once on the way out, so both kinds come back as
6.00 in. A strip and an opening that are off by the same amount get the
same number; there is no per-kind weighting and none was asked for.
"""
o1 = {'kind': B.OPENING, 'x0': 4.0, 'x1': 6.0, 'y0': 2.0, 'y1': 5.0}
o2 = {'kind': B.OPENING, 'x0': 4.5, 'x1': 6.0, 'y0': 2.0, 'y1': 5.0}
s1 = {'kind': B.STRIP_Y, 'x0': 4.0, 'x1': 6.0, 'y0': 2.0, 'y1': 5.0,
'strip_ft': 3.0}
s2 = {'kind': B.STRIP_Y, 'x0': 4.5, 'x1': 6.0, 'y0': 2.0, 'y1': 5.0,
'strip_ft': 3.0}
assert B.covers(o2, o1) == pytest.approx(6.0) # 0.5 ft -> 6 in
assert B.covers(s2, s1) == pytest.approx(6.0)
def test_the_feet_to_inch_conversion_happens_exactly_once():
"""THE 12x GUARD. This project has already lost time to a conversion
applied at the wrong boundary, so the factor is pinned by test.
The records are and stay feet -- `covers` must not mutate them -- and the
returned distance is exactly twelve times the feet figure, not once and
not one hundred and forty-four times.
"""
a = {'kind': B.OPENING, 'x0': 0.0, 'x1': 10.0, 'y0': 0.0, 'y1': 10.0}
b = {'kind': B.OPENING, 'x0': 1.0, 'x1': 10.0, 'y0': 0.0, 'y1': 10.0}
assert B.covers(b, a) == pytest.approx(12.0) # 1.0 ft of offset
assert a['x0'] == 0.0 and b['x0'] == 1.0 # records untouched
assert B.EXACT_TOL_IN == pytest.approx(B.EXACT_TOL_FT * 12.0)
# ------------------------------------------------------------- the grain
#
# Two decimal inches is 0.01 in, an order of magnitude finer than any
# tolerance this tool uses. These are the tests that keep the DISPLAY the
# owner asked for from turning into a claim of PRECISION nobody measured.
def test_a_non_exact_distance_lands_on_the_eighth_inch_grain():
"""Every distance the report can print is a multiple of 1/8 in."""
a = {'kind': B.OPENING, 'x0': 0.0, 'x1': 10.0, 'y0': 0.0, 'y1': 10.0}
for offset_ft in (0.05, 0.1, 0.2, 0.37, 0.5, 1.0, 2.13):
b = dict(a, x0=offset_ft)
got = B.covers(b, a)
steps = got / B.GRAIN_IN
assert steps == pytest.approx(round(steps), abs=1e-9), (offset_ft, got)
def test_differences_finer_than_the_grain_do_not_reorder_anything():
"""0.01 in apart is not a difference this tool can measure, so the two
donors come back EQUAL and fall through to the next tie-break rather than
being separated by noise."""
t = {'kind': B.OPENING, 'x0': 0.0, 'x1': 10.0, 'y0': 0.0, 'y1': 10.0}
near = dict(t, x0=0.0400) # 0.480 in of offset
nearer = dict(t, x0=0.0392) # 0.470 in of offset -- 0.01 in closer
assert B.covers(near, t) == B.covers(nearer, t)
assert B.covers(near, t) == pytest.approx(0.5)
def test_the_grain_never_swallows_the_difference_between_off_and_exact():
"""Quantizing to 1/8 in would round a 1/16 in miss down to zero, and zero
means EXACT -- the one word in this report that has to keep meaning
measured-identical. A hair off is floored, never rounded to exact."""
t = {'kind': B.OPENING, 'x0': 0.0, 'x1': 10.0, 'y0': 0.0, 'y1': 10.0}
hair = dict(t, x0=0.004) # 0.048 in -- under half a grain step
got = B.covers(hair, t)
assert got > 0.0
assert got == pytest.approx(B.EXACT_TOL_IN)
assert B.covers(t, t) == 0.0
def test_through_and_blind_are_not_the_same_reinforcing():
a = {'kind': B.OPENING, 'x0': 4.0, 'x1': 6.0, 'y0': 2.0, 'y1': 5.0,
'through': True}
b = dict(a, through=False)
assert B.covers(a, b) is None
assert B.covers(a, dict(a)) == 0.0
def test_unjudged_penetration_is_not_read_as_blind():
"""`through=None` is could-not-judge. Treating it as False would invent a
judgement nobody made -- the standing rule on this project."""
through = {'kind': B.OPENING, 'x0': 4.0, 'x1': 6.0, 'y0': 2.0, 'y1': 5.0,
'through': True}
unjudged = dict(through, through=None)
blind = dict(through, through=False)
assert B.covers(unjudged, through) == 0.0
assert B.covers(through, unjudged) == 0.0
assert B.covers(unjudged, blind) == 0.0
assert B.covers(blind, through) is None
# --------------------------------------------- the approximate-outline flag
def test_an_approximated_edge_never_scores_exact():
"""A piece whose outline the index cannot see must not be reported as an
exact edge match. It ranks just behind exact, and is never called exact."""
p = piece('PNL620', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
exact = B.features_for(p, outline_approximate=False)
approx = B.features_for(p, outline_approximate=True)
edge = [i for i, f in enumerate(exact) if f['between'] == B.VOID_EDGE]
assert edge
for i in edge:
assert B.covers(exact[i], exact[i]) == 0.0
assert B.covers(approx[i], exact[i]) == B.EXACT_TOL_IN
assert B.covers(exact[i], approx[i]) == B.EXACT_TOL_IN
def test_an_approximated_piece_still_covers_interior_ligaments_exactly():
"""The flag is about edges. A strip between two voids does not touch the
outline, so nothing about it was approximated."""
p = piece('PNL621', 20.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (9.0, 11.0, 2.0, 5.0)])
exact = B.features_for(p, outline_approximate=False)
approx = B.features_for(p, outline_approximate=True)
i = exact.index(find(exact, B.STRIP_X, 6.0, 9.0, 2.0, 5.0))
assert B.covers(approx[i], exact[i]) == 0.0
def test_an_approximate_donor_ranks_behind_an_exact_one():
"""End to end: the flag has to change the ANSWER, not just a field."""
target = piece('PNL622', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
good = piece('PNL623', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
approx = piece('PNL624', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
sug, info = B.propose(target, [good, approx], donor_filter=PNL,
approximate={'PNL624'})
assert sug.best.donors == ('PNL623',)
assert info['approximate_in_pool'] == ['PNL624']
# ------------------------------------------------------------ the filter
def base(name, thickness=8.0, width=10.0, **kw):
return piece(name, 20.0, width, thickness, [(4.0, 6.0, 2.0, 5.0)], **kw)
# Marks here are the project's `PNL...` placeholders, so the tests state the
# prefix they mean rather than borrowing the real one. That the SHIPPED
# default is wall-panels-only is asserted directly, just below.
PNL = B.DonorFilter(prefixes=('PNL',))
def test_the_shipped_default_declares_no_prefix_of_its_own():
"""The owner's ruling still stands -- only wall panels donate -- but it
is a JOB fact now, declared in the job knowledge and handed in by
`suggest_for_piece` (see vibe/scope.py). A prefix baked in here would be
one job's division of labour hardcoded into a shareable repository,
which is the same silent exclusion this codebase exists to refuse.
None means no prefix rule, which is what an UNDECLARED scope must
produce: judge everything, and say so on the report.
"""
assert B.DonorFilter().prefixes is None
def test_only_the_wanted_prefix_survives():
kept, rejected = B.select_donors(
[base('PNL002'), base('BM001'), base('SS001'), base('CL001')],
base('PNL001'), PNL)
assert [r['name'] for r in kept] == ['PNL002']
assert rejected['prefix'] == ['BM001', 'CL001', 'SS001']
def test_thickness_must_match():
kept, rejected = B.select_donors(
[base('PNL002', thickness=8.0), base('PNL003', thickness=12.0)],
base('PNL001', thickness=8.0), PNL)
assert [r['name'] for r in kept] == ['PNL002']
assert rejected['thickness'] == ['PNL003']
def test_width_is_not_filtered_by_default():
"""The arguable one. Off by default so a filter never excludes a
better-shaped donor -- the owner's standing correction."""
assert B.DonorFilter().max_width_diff_ft is None
kept, _ = B.select_donors([base('PNL002', width=30.0)],
base('PNL001', width=10.0), PNL)
assert [r['name'] for r in kept] == ['PNL002']
def test_width_can_be_switched_on():
kept, rejected = B.select_donors(
[base('PNL002', width=30.0), base('PNL003', width=10.5)],
base('PNL001', width=10.0),
B.DonorFilter(prefixes=('PNL',), max_width_diff_ft=1.0))
assert [r['name'] for r in kept] == ['PNL003']
assert rejected['width'] == ['PNL002']
def test_a_piece_is_not_its_own_donor():
kept, rejected = B.select_donors(
[base('PNL001'), base('PNL002')], base('PNL001'), PNL)
assert [r['name'] for r in kept] == ['PNL002']
assert rejected['self'] == ['PNL001']
def test_on_hold_is_never_a_donor():
"""The index already drops these; the filter re-asserts it, because a
record can reach `propose` from somewhere other than the cache."""
kept, rejected = B.select_donors(
[base('PNL002', on_hold=1), base('PNL003', reinforced=0)],
base('PNL001'), PNL)
assert kept == []
assert rejected['not_eligible'] == ['PNL002', 'PNL003']
def test_never_measured_and_measured_empty_are_rejected_separately():
"""The distinction the index keeps must survive the filter."""
unjudged = core.piece_record('PNL002', 1, 'sig', 1, 0, error='no solid')
empty = piece('PNL003', 20.0, 10.0, 8.0, [])
kept, rejected = B.select_donors([unjudged, empty], base('PNL001'), PNL)
assert kept == []
assert rejected['unjudged'] == ['PNL002']
assert rejected['no_features'] == ['PNL003']
# --------------------------------- require_features INVERTS for a featureless
# target (owner, 2026-09-01, hit on a real WP2.0 piece with no openings): "如
# 果扫描到目标没有opening,那么就找另一块没有opening的板子给target当doner。"
def test_a_featureless_donor_is_kept_when_the_target_is_also_featureless():
"""The reported defect, as a fixture: WP397-shaped, not WP397. A target
measured to have no openings must not have its featureless donor dropped
by the same rule that (correctly) drops one when the target has voids."""
target = piece('PNL001', 20.0, 10.0, 8.0, [])
twin = piece('PNL002', 20.0, 10.0, 8.0, [])
kept, rejected = B.select_donors([twin], target, PNL)
assert [r['name'] for r in kept] == ['PNL002']
assert 'no_features' not in rejected
def test_the_inversion_does_not_relax_design_thickness_or_scope():
"""The owner's very next sentence: "很多其他东西依然是有用的,比如说design
number。" One rule inverted; the rest of the filter is unmoved."""
target = piece('PNL001', 20.0, 10.0, 8.0, [], design='PNL2.0')
wrong_design = piece('PNL002', 20.0, 10.0, 8.0, [], design='PNL1.0')
wrong_thickness = piece('PNL003', 20.0, 10.0, 12.0, [], design='PNL2.0')
out_of_scope = piece('BM001', 20.0, 10.0, 8.0, [], design='PNL2.0')
kept, rejected = B.select_donors(
[wrong_design, wrong_thickness, out_of_scope], target, PNL)
assert kept == []
assert rejected['design'] == ['PNL002']
assert rejected['thickness'] == ['PNL003']
assert rejected['prefix'] == ['BM001']
def test_an_unjudged_target_does_not_take_the_inverted_path():
"""`features is None` (never measured) must NOT read as `features == []`
(measured, empty) -- the project's cardinal distinction. A donor nobody
would want to see offered for a piece nobody could even measure."""
unjudged_target = core.piece_record('PNL001', 1, 'sig', 1, 0,
error='no solid')
featureless_donor = piece('PNL002', 20.0, 10.0, 8.0, [])
kept, rejected = B.select_donors([featureless_donor], unjudged_target,
PNL)
assert kept == []
assert rejected['no_features'] == ['PNL002']
def test_a_donor_with_features_survives_a_featureless_target_too():
"""Never rejected for this reason either way -- the question of whether
it should rank behind a featureless twin is `shape_search_for`'s, not the
filter's."""
target = piece('PNL001', 20.0, 10.0, 8.0, [])
has_features = base('PNL002')
kept, _rejected = B.select_donors([has_features], target, PNL)
assert [r['name'] for r in kept] == ['PNL002']
# --------------------------------------------- the featureless-target search
def test_shape_search_ranks_featureless_donors_above_ones_with_openings():
target = piece('PNL001', 20.0, 10.0, 8.0, [])
featureless = piece('PNL002', 20.0, 10.0, 8.0, [])
has_features = base('PNL003')
search = B.shape_search_for(target, [has_features, featureless])
assert [r['name'] for r in search['eligible']] == ['PNL002']
assert [r['name'] for r in search['secondary']] == ['PNL003']
assert search['considered'] == 2
def test_shape_search_ranks_the_closer_shape_first():
target = piece('PNL001', 20.0, 10.0, 8.0, [])
close = piece('PNL002', 20.5, 10.0, 8.0, [])
far = piece('PNL003', 24.0, 10.0, 8.0, [])
search = B.shape_search_for(target, [far, close])
assert [r['name'] for r in search['eligible']] == ['PNL002', 'PNL003']
assert search['degenerate'] is False
def test_shape_search_flags_a_genuine_tie_as_degenerate():
"""Two panels of the same design very often ARE the same length and
width -- see `precast-nomenclature`. Ranking a coin flip as an order
would be a false precision this tool refuses everywhere else."""
target = piece('PNL001', 20.0, 10.0, 8.0, [])
twin_a = piece('PNL003', 20.0, 10.0, 8.0, [])
twin_b = piece('PNL002', 20.0, 10.0, 8.0, [])
search = B.shape_search_for(target, [twin_a, twin_b])
assert search['degenerate'] is True
# Still ordered -- by name, the last tie-break -- just not claimed as a
# ranking by fit.
assert [r['name'] for r in search['eligible']] == ['PNL002', 'PNL003']
def test_shape_search_one_donor_is_not_degenerate():
"""Nothing to rank between is a plain single answer, not a tie."""
target = piece('PNL001', 20.0, 10.0, 8.0, [], design='PNL2.0')
lone = piece('PNL002', 20.0, 10.0, 8.0, [], design='PNL2.0')
search = B.shape_search_for(target, [lone])
assert search['degenerate'] is False
assert [r['name'] for r in search['eligible']] == ['PNL002']
def test_propose_finds_the_featureless_donor_for_a_featureless_target():
"""End to end, off Revit: the fixture analogue of the real defect. A
target with no openings must come back with its matching, featureless
donor as the eligible pool, must not reject it, and must still refuse a
donor of a different design."""
target = piece('PNL2_001', 26.4167, 9.8333, 8.0, [], design='PNL2.0')
twin = piece('PNL2_002', 26.4167, 9.8333, 8.0, [], design='PNL2.0')
wrong_design = piece('PNL1_001', 26.4167, 9.8333, 8.0, [],
design='PNL1.0')
has_openings = base('PNL2_003', design='PNL2.0')
sug, info = B.propose(target, [twin, wrong_design, has_openings],
donor_filter=PNL)
assert sug is None
assert info['target_status'] == 'no_features'
search = info['shape_search']
assert search['ran'] is True
assert [r['name'] for r in search['eligible']] == ['PNL2_002']
assert [r['name'] for r in search['secondary']] == ['PNL2_003']
all_named = ([r['name'] for r in search['eligible']] +
[r['name'] for r in search['secondary']])
assert 'PNL1_001' not in all_named
assert info['rejected_names']['design'] == ['PNL1_001']
assert 'no_features' not in info['rejected_names']
# ------------------------------------------------- the design-number filter
#
# Owner, 2026-09-01: "选择母版的目标,必须得是跟自己的design number一样的panel。
# 我刚在一个WP2.0上面跑了reinforce,给我俩WP1.0的母版,压根用不了。" 必须 -- a
# filter, not a ranking term. Every test below is about that one word.
def test_a_donor_of_another_design_is_not_a_donor():
"""The reported defect, as one test: a `PNL2.0` target offered `PNL1.0`
templates. It must not be a low-ranked suggestion; it must be gone."""
kept, rejected = B.select_donors(
[base('PNL002', design='PNL1.0'), base('PNL003', design='PNL2.0')],
base('PNL001', design='PNL2.0'), PNL)
assert [r['name'] for r in kept] == ['PNL003']
assert rejected['design'] == ['PNL002']
def test_the_same_design_survives_and_nothing_else_does():
kept, _rejected = B.select_donors(
[base('PNL002', design='PNL2.0'), base('PNL003', design='PNL2.0'),
base('PNL004', design='PNL1.0'), base('PNL005', design='PNL30.0')],
base('PNL001', design='PNL2.0'), PNL)
assert [r['name'] for r in kept] == ['PNL002', 'PNL003']
def test_a_packet_suffix_is_not_a_different_design():
"""The established nomenclature ruling, reused rather than reinvented:
`.0` is a cover sheet, `.A` is a note further into the same packet, and a
piece may carry the bare number. One design, one family, four spellings.
This is `specformat.design_key` -- the same reduction Ticket QC already
checks a piece against its ticket with -- and not a rule written here.
"""
kept, rejected = B.select_donors(
[base('PNL002', design='PNL1.A'), base('PNL003', design='PNL1'),
base('PNL004', design='PNL1.B1'), base('PNL005', design='PNL2.A')],
base('PNL001', design='PNL1.0'), PNL)
assert [r['name'] for r in kept] == ['PNL002', 'PNL003', 'PNL004']
assert rejected['design'] == ['PNL005']
def test_a_donor_whose_design_could_not_be_read_is_refused_not_assumed():
"""COULD NOT JUDGE IS NOT A MATCH. `None == None` is true in Python and
false in precast: two pieces nobody read are not the same design."""
kept, rejected = B.select_donors(
[base('PNL002', design=None), base('PNL003', design=' '),
base('PNL004', design='...')],
base('PNL001', design='PNL1.0'), PNL)
assert kept == []
assert rejected['design_unknown'] == ['PNL002', 'PNL003', 'PNL004']
def test_a_target_with_no_readable_design_matches_nobody():
kept, rejected = B.select_donors(
[base('PNL002', design='PNL1.0')], base('PNL001', design=None), PNL)
assert kept == []
assert rejected['design_target_unknown'] == ['PNL002']
def test_the_design_rule_is_on_by_default():
assert B.DonorFilter().match_design is True
assert B.DonorFilter().design_re is None
def test_the_scope_is_reported_before_the_design():
"""Another engineer's beam is out of SCOPE; it was never a candidate, and
calling it a design mismatch would bury the real reason."""
_kept, rejected = B.select_donors(
[base('BM001', design='BM9.0')], base('PNL001', design='PNL1.0'), PNL)
assert rejected == {'prefix': ['BM001']}
def test_the_plant_pattern_is_used_when_one_is_given():
"""`nomenclature.design_number_re` is plant knowledge and is handed in,
never read here -- this module has to run with no knowledge layer at all.
A pattern that stops at the letters makes PNL1 and PNL2 one design."""
loose = B.DonorFilter(prefixes=('PNL',), design_re=r'^([A-Za-z]+)')
kept, _rejected = B.select_donors(
[base('PNL002', design='PNL2.0')],
base('PNL001', design='PNL1.0'), loose)
assert [r['name'] for r in kept] == ['PNL002']
def test_ranking_inside_one_design_is_untouched():
"""The filter removes candidates; it must not reorder the survivors. Same
three donors, same target, with and without a cross-design distractor in
the pool: identical proposals in identical order."""
target = piece('PNL801', 20.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (10.0, 12.0, 2.0, 5.0)])
near = piece('PNL802', 20.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (10.0, 12.0, 2.0, 5.0)])
far = piece('PNL803', 20.0, 10.0, 8.0,
[(4.05, 6.05, 2.0, 5.0), (10.05, 12.05, 2.0, 5.0)])
other = piece('PNL804', 20.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (10.0, 12.0, 2.0, 5.0)],
design='PNL9.0')
clean, _i = B.propose(target, [near, far], donor_filter=PNL)
mixed, _j = B.propose(target, [near, far, other], donor_filter=PNL)
assert clean.status == mixed.status
assert ([p.donors for p in clean.proposals] ==
[p.donors for p in mixed.proposals])
assert ([p.distances for p in clean.proposals] ==
[p.distances for p in mixed.proposals])
assert 'PNL804' not in (mixed.best.donors or ())
# --------------------------------------------- the four design refusals
#
# None of them may degrade into offering a donor of another design, labelled
# or otherwise. `propose` returns NO suggestion for every one.
def test_no_donor_of_this_design_refuses_rather_than_offering_another():
target = piece('PNL901', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
design='PNL2.0')
pool = [piece('PNL902', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
design='PNL1.0'),
piece('PNL903', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
design='PNL1.A')]
sug, info = B.propose(target, pool, donor_filter=PNL)
assert sug is None # not a ranked list of PNL1s
assert info['design']['status'] == B.DESIGN_NONE_MATCH
assert info['design']['refused'] is True
assert info['design']['target_key'] == 'PNL2'
assert info['design']['candidates'] == 2
assert info['design']['designs_seen'] == {'PNL1': 2}
def test_an_index_that_never_recorded_the_design_is_unjudged_not_matching():
"""A record written before the field existed. It is not evidence of
anything, least of all of a match."""
target = piece('PNL911', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
design='PNL2.0')
old = base('PNL912')
del old['design_number']
sug, info = B.propose(target, [old], donor_filter=PNL)
assert sug is None
assert info['design']['status'] == B.DESIGN_INDEX_NOT_RECORDED
assert info['design']['index_status'] == core.DESIGN_NOT_RECORDED
def test_an_index_whose_design_numbers_are_all_empty_is_unjudged():
"""Measured on the real index, 2026-09-01: 773 pieces, every one of them
`design_number: null`, because the build ran with no knowledge layer. The
field was there; nobody had read it. Not one donor may be offered off
that, and the refusal has to name a different fix from the one above."""
target = piece('PNL921', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
design='PNL2.0')
blank = [base('PNL922', design=None), base('PNL923', design=None)]
sug, info = B.propose(target, blank, donor_filter=PNL)
assert sug is None
assert info['design']['status'] == B.DESIGN_INDEX_UNREAD
assert info['design']['index_status'] == core.DESIGN_UNREAD
def test_a_target_with_no_design_number_refuses_before_it_compares():
target = piece('PNL931', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
design=None)
pool = [base('PNL932', design='PNL1.0')]
sug, info = B.propose(target, pool, donor_filter=PNL)
assert sug is None
assert info['design']['status'] == B.DESIGN_TARGET_UNKNOWN
def test_a_pool_emptied_before_the_design_test_is_not_a_design_refusal():
"""The scope, eligibility and 'never measured' all empty the pool BEFORE
the design is looked at. Blaming the design rule for their work would hide
the real reason under a confident sentence, so the design verdict stands
down and NO_DONORS -- the older finding -- is what the page reports."""
target = piece('PNL941', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
design='PNL2.0')
held = base('PNL942', design='PNL1.0', on_hold=1)
sug, info = B.propose(target, [held], donor_filter=PNL)
assert info['design']['refused'] is False
assert info['design']['ran'] is False
assert sug is not None and sug.status == match.NO_DONORS
def test_the_four_refusals_are_four_different_answers():
"""They have four different fixes -- rebuild the index, map the role, fix
the piece, detail a first one by hand -- so they may never collapse."""
assert len(set(B.DESIGN_REFUSALS)) == 4
assert B.DESIGN_OK not in B.DESIGN_REFUSALS
def test_every_rejection_is_named_and_counted():
kept, rejected = B.select_donors(
[base('PNL001'), base('BM001'), base('PNL002', thickness=12.0),
base('PNL003')], base('PNL001'), PNL)
assert [r['name'] for r in kept] == ['PNL003']
assert set(rejected) == {'self', 'prefix', 'thickness'}
# -------------------------------------------------------------- end to end
def test_the_worked_example_shape_picks_the_matching_donor():
"""Rebuilt from the worked example with invented marks: a donor that
matches the left two-thirds, and a distractor that matches nothing."""
target = piece('PNL701', 27.625, 11.5, 8.0, [
(0.0, 0.875, 1.125, 3.0), (0.0, 0.667, 11.292, 11.5, False),
(6.5, 10.583, 0.354, 4.479), (14.344, 18.427, 0.354, 4.479),
(24.042, 25.875, 1.125, 3.0), (24.25, 27.625, 6.25, 11.5)])
twin = piece('PNL702', 24.917, 11.5, 8.0, [
(0.0, 0.875, 1.125, 3.0), (0.0, 0.667, 11.292, 11.5, False),
(6.5, 10.583, 0.354, 4.479), (14.344, 18.427, 0.354, 4.479),
(24.042, 24.917, 1.125, 3.0), (24.25, 24.917, 11.292, 11.5, False)])
other = piece('PNL703', 21.0, 11.5, 8.0, [(3.0, 4.0, 7.0, 9.0)])
sug, info = B.propose(target, [twin, other], donor_filter=PNL)
assert sug.status == match.PARTIAL
assert 'PNL702' in sug.best.donors
assert sug.best.exact_count > 0
# The right-end features have no donor here, and the result says so
# rather than quietly covering them.
assert sug.uncovered
def test_no_donors_is_not_no_coverage():
target = base('PNL001')
sug, info = B.propose(target, [], donor_filter=PNL)
assert sug.status == match.NO_DONORS
assert info['donors'] == 0
def test_a_target_never_measured_yields_no_suggestion():
target = core.piece_record('PNL001', 1, 'sig', 1, 0, error='no solid')
sug, info = B.propose(target, [base('PNL002')], donor_filter=PNL)
assert sug is None
assert info['target_status'] == 'unjudged'
def test_a_target_measured_with_no_voids_is_a_different_answer():
sug, info = B.propose(piece('PNL001', 20.0, 10.0, 8.0, []),
[base('PNL002')], donor_filter=PNL)
assert sug is None
assert info['target_status'] == 'no_features'
def test_explain_names_the_donor_for_every_target_feature():
target = base('PNL001')
sug, info = B.propose(target, [base('PNL002')], donor_filter=PNL)
rows = B.explain(sug, info)
assert len(rows) == len(info['target_features'])
assert all(r['donor'] == 'PNL002' and r['exact'] for r in rows)
def test_explain_reports_an_uncovered_feature_as_uncovered():
target = piece('PNL001', 20.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (14.0, 16.0, 2.0, 5.0)])
donor = piece('PNL002', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
sug, info = B.propose(target, [donor], donor_filter=PNL)
rows = B.explain(sug, info)
assert [r['donor'] for r in rows].count(None) > 0
def test_explain_surfaces_registry_feature_ids_for_target_and_donor():
"""The rows carry the shared-vocabulary ids so a reader can see the
numbering. An exact-twin donor shares the target's descriptor, hence its
id -- 'target #k <-> donor #k'."""
target = base('PNL001')
donor = base('PNL002')
sug, info = B.propose(target, [donor], donor_filter=PNL)
# Stamp the vocabulary the way `suggest_from_index` does: built from the
# donor pool, carried as the plain registry dict.
cache = core.new_cache('m')
core.register_features(cache, [donor])
info['registry'] = cache['registry']
rows = B.explain(sug, info)
assert rows
row = rows[0]
assert row['target_feature_id'] is not None
assert row['donor_feature_id'] == row['target_feature_id']
def test_explain_target_id_is_none_when_no_donor_carries_the_shape():
"""A target feature whose SHAPE no donor produced projects to None -- a
read-only lookup miss, the informative "nobody has this shape" signal, and
it does not grow the vocabulary."""
target = piece('PNL001', 20.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (14.0, 17.0, 2.0, 6.0)])
donor = piece('PNL002', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
sug, info = B.propose(target, [donor], donor_filter=PNL)
cache = core.new_cache('m')
core.register_features(cache, [donor])
next_before = core.Registry.deserialize(cache['registry']).serialize()['next_id']
info['registry'] = cache['registry']
rows = B.explain(sug, info)
# the target feature the donor cannot cover has a shape no donor produced
novel = [r for r in rows if r['donor'] is None]
assert novel
assert all(r['target_feature_id'] is None for r in novel)
# the read-only projection did not assign it a fresh id
next_after = core.Registry.deserialize(info['registry']).serialize()['next_id']
assert next_after == next_before
# --------------------------------------------------- MASTER, end to end
#
# The index records it, the matcher ranks on it, and this is the join. Two
# things have to hold here and nowhere else: the pool's masters are reported
# AFTER the donor filter (a master the thickness filter dropped is not one
# this answer could have used), and the flag reaches the matcher at all.
def test_the_pool_reports_only_the_masters_that_survived_the_filter():
target = base('PNL001')
kept_master = base('PNL002', master=True)
dropped_master = base('PNL003', thickness=12.0, master=True)
plain = base('PNL004')
sug, info = B.propose(target, [kept_master, dropped_master, plain],
donor_filter=PNL)
assert info['master_donors'] == ['PNL002']
assert 'PNL003' in info['rejected_names']['thickness']
def test_a_pool_with_no_master_says_so_with_an_empty_list_not_a_missing_key():
sug, info = B.propose(base('PNL001'), [base('PNL002')], donor_filter=PNL)
assert info['master_donors'] == []
def test_the_master_flag_reaches_the_ranking():
"""Two identical donors, one reviewed. The reviewed one is proposed first.
They are geometrically indistinguishable -- same rectangle, same panel --
so the distance vectors are equal and only the tie-break separates them.
PNL002 is listed first, so input order alone would put it on top.
"""
target = base('PNL001')
sug, info = B.propose(target, [base('PNL002'), base('PNL003', master=True)],
donor_filter=PNL)
assert sug.best.donors == ('PNL003',)
assert sug.best.masters == ('PNL003',)
assert sug.proposals[1].donors == ('PNL002',)
def test_a_master_does_not_outrank_a_better_fitting_donor():
"""The owner's ruling, held at the layer that actually runs on the index.
PNL003 is reviewed but its opening is 2 ft off; PNL002 is an exact twin
of the target and is not reviewed. Fit wins.
"""
target = piece('PNL001', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
twin = piece('PNL002', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
loose = piece('PNL003', 20.0, 10.0, 8.0, [(4.5, 6.5, 2.0, 5.0)],
master=True)
sug, info = B.propose(target, [twin, loose], donor_filter=PNL)
assert sug.best.donors == ('PNL002',)
assert sug.best.master_count == 0
def test_explain_rows_carry_whether_the_covering_donor_was_reviewed():
target = base('PNL001')
sug, info = B.propose(target, [base('PNL002', master=True)],
donor_filter=PNL)
rows = B.explain(sug, info)
assert rows
assert all(r['donor_master'] for r in rows if r['donor'] is not None)
def test_an_unread_signal_is_reported_as_not_run_not_as_no_masters():
"""Every donor `master=None` -- the role is unmapped, nothing was read."""
target = base('PNL001')
pool = [base('PNL002'), base('PNL003')]
for rec in pool:
rec['master'] = None
sug, info = B.propose(target, pool, donor_filter=PNL)
assert info['master_donors'] == []
assert info['master_unjudged'] is True
def test_a_pool_that_was_read_is_never_reported_as_unjudged():
sug, info = B.propose(base('PNL001'), [base('PNL002')], donor_filter=PNL)
assert info['master_unjudged'] is False
# --------------------------------------------- SAME ELEVATION, end to end
#
# The incident, and the ruling that fixed it. Owner, 2026-09-02, on a real
# run against WP425: five donors tied on every existing criterion -- 1
# donor, 5/5 covered, 4 exact, 0 reviewed, 0.04 in total distance, all five
# identical -- and the tie fell through to mark order, so WP133 printed
# first though WP234 shares WP425's own building elevation:
# "WP234明明在同一个elevation,为什么排名没有提前?" Approved as briefed the
# same day ("同意,就这么做"): elevation is an AFFINITY, the LAST tie-break,
# never a filter -- a cross-elevation donor with better coverage still wins.
#
# RULED AGAIN THE SAME DAY: elevation is a purely GEOMETRIC fact (a
# thickness-axis coordinate band), never a hand-typed parameter -- see
# `reinforcecore.elevation_band`'s module note. Fixtures below use `band(tag)`
# (defined above, next to `piece`/`base`) rather than a bare string: the same
# `tag` always returns the identical band, so `band('ELEV-3')` on two
# fixtures genuinely means "the same wall plane" the way a shared string
# label used to.
def test_the_incident_five_tied_donors_one_shares_elevation_wins():
"""WP425, reproduced with invented marks. Five donors, geometrically
identical to the target and to each other -- a dead tie on donor count,
exactness, MASTER and total distance -- and only one shares the
target's building elevation band. It ranks first, and the report can
say why: `sug.best.same_elevation` names it, exactly as `masters` would.
Without the affinity term this fell through to mark order and printed
the alphabetically-first donor instead of the one actually on the
target's own elevation -- PNL133, not PNL234, which is exactly what
happened on the real run this reproduces.
"""
target = base('PNL425', elevation_band=band('ELEV-3'))
donors = [
base('PNL133', elevation_band=band('ELEV-1')),
base('PNL166', elevation_band=band('ELEV-2')),
base('PNL234', elevation_band=band('ELEV-3')),
base('PNL267', elevation_band=band('ELEV-4')),
base('PNL271', elevation_band=None),
]
sug, info = B.propose(target, donors, donor_filter=PNL)
assert sug.best.donors == ('PNL234',)
assert sug.best.same_elevation == ('PNL234',)
assert info['target_elevation'] == {'group': None, 'band': band('ELEV-3')}
assert info['same_elevation_donors'] == ['PNL234']
assert info['same_elevation_sources'] == {'PNL234': core.ELEVATION_BY_BAND}
def test_cross_elevation_donor_with_better_coverage_still_wins():
"""The ranking-not-filtering rule, as an executable statement.
PNL501 is on a different elevation and fits the target's opening
exactly. PNL502 shares the target's elevation but is 0.5 ft off. Fit
wins, every time -- elevation never promotes a worse-shaped donor past
one the geometry has already ranked ahead of it.
"""
target = piece('PNL425', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
elevation_band=band('ELEV-3'))
exact_other_elevation = piece(
'PNL501', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
elevation_band=band('ELEV-9'))
loose_same_elevation = piece(
'PNL502', 20.0, 10.0, 8.0, [(4.5, 6.5, 2.0, 5.0)],
elevation_band=band('ELEV-3'))
sug, info = B.propose(target, [exact_other_elevation,
loose_same_elevation], donor_filter=PNL)
assert sug.best.donors == ('PNL501',)
assert sug.best.same_elevation == ()
def test_a_target_with_no_determined_elevation_prefers_nobody():
"""UNKNOWN IS A STATE, NOT A BLANK. The target's own elevation band
could not be determined, so nothing in the pool can be preferred on it
-- not even a donor whose band happens to be equally undetermined."""
target = base('PNL425', elevation_band=None)
donors = [base('PNL133', elevation_band=band('ELEV-1')),
base('PNL166', elevation_band=None)]
sug, info = B.propose(target, donors, donor_filter=PNL)
assert info['same_elevation_donors'] == []
assert sug.best.same_elevation == ()
def test_a_donor_with_no_determined_elevation_is_never_preferred():
"""The reverse case: the TARGET's elevation band is known, but a
donor's own could not be determined. That donor is never added to the
affinity set, even though a real match might exist -- could-not-judge
is never guessed as a match."""
target = base('PNL425', elevation_band=band('ELEV-1'))
donors = [base('PNL133', elevation_band=None),
base('PNL166', elevation_band=band('ELEV-9'))]
sug, info = B.propose(target, donors, donor_filter=PNL)
assert info['same_elevation_donors'] == []
def test_a_record_missing_the_elevation_band_key_entirely_does_not_crash():
"""A pre-migration cache record -- built before this field existed --
has no 'elevation_band' key at all, not even one holding None. The
affinity computation must read that the same as an explicit None rather
than raising, because a stale cache is exactly what the first press
after this change serves before a refresh rebuilds it."""
target = base('PNL425', elevation_band=band('ELEV-1'))
donor = base('PNL133', elevation_band=band('ELEV-1'))
del donor['elevation_band']
sug, info = B.propose(target, [donor], donor_filter=PNL)
assert info['same_elevation_donors'] == []
assert sug.best.same_elevation == ()
def test_a_pool_with_no_same_elevation_donor_says_so_with_an_empty_list():
sug, info = B.propose(base('PNL425', elevation_band=band('ELEV-1')),
[base('PNL133', elevation_band=band('ELEV-9'))],
donor_filter=PNL)
assert info['same_elevation_donors'] == []
def test_a_perpendicular_axis_donor_never_matches_even_numerically_close():
"""The owner's explicit confirmation: a donor thin in global Y never
shares an elevation with a target thin in global X, however close the
coordinates happen to be -- that is a wall returning a corner, not the
same wall plane."""
target = base('PNL425', elevation_band={'axis': 'X', 'min': 100.0,
'max': 100.667})
donor = base('PNL133', elevation_band={'axis': 'Y', 'min': 100.0,
'max': 100.667})
sug, info = B.propose(target, [donor], donor_filter=PNL)
assert info['same_elevation_donors'] == []
assert sug.best.same_elevation == ()
def test_a_donor_whose_band_only_abuts_the_targets_does_not_match():
"""The pinned edge case: touching at exactly one coordinate, no
interior overlap, is a stepped facade, not a shared wall plane."""
target = base('PNL425', elevation_band={'axis': 'X', 'min': 100.0,
'max': 100.667})
donor = base('PNL133', elevation_band={'axis': 'X', 'min': 100.667,
'max': 101.334})
sug, info = B.propose(target, [donor], donor_filter=PNL)
assert info['same_elevation_donors'] == []
assert sug.best.same_elevation == ()
# ---------------------------------------- THE ELEVATION ACCELERATOR (group)
#
# Owner's ruling, 2026-09-02, refining the geometric-only ruling the SAME
# day once MC's real model turned up a usable grouping parameter:
# "对MC而言,所有的墙应该都有一个参数叫Tagged_Sheet。如果俩panel这个参数一
# 样,那么他们就是同一个elevation,不用跑哪个几何引擎。" It is checked FIRST
# where it exists, but geometry stays the floor -- most jobs (plenty of
# plants, simple MC jobs) never map it, and that absence is normal, not a
# stand-down.
def test_same_group_matches_with_no_geometry_agreement_at_all():
"""The shortcut, at its starkest: matching groups, PERPENDICULAR bands
(which would never agree geometrically) -- the group still decides it,
with `core.ELEVATION_BY_GROUP` naming the source."""
target = base('PNL425', elevation_group='E3.16',
elevation_band={'axis': 'X', 'min': 100.0, 'max': 100.667})
donor = base('PNL133', elevation_group=' e3.16 ',
elevation_band={'axis': 'Y', 'min': 500.0, 'max': 500.667})
sug, info = B.propose(target, [donor], donor_filter=PNL)
assert info['same_elevation_donors'] == ['PNL133']
assert info['same_elevation_sources'] == {'PNL133': core.ELEVATION_BY_GROUP}
assert sug.best.same_elevation == ('PNL133',)
def test_a_different_group_falls_back_to_geometry_rather_than_vetoing_it():
"""A group mismatch does not exclude the donor -- it just fails to
answer tier 1, and the geometric floor gets to try (and here, agrees)."""
shared = {'axis': 'X', 'min': 100.0, 'max': 100.667}
target = base('PNL425', elevation_group='E3.16', elevation_band=shared)
donor = base('PNL133', elevation_group='E3.22', elevation_band=shared)
sug, info = B.propose(target, [donor], donor_filter=PNL)
assert info['same_elevation_donors'] == ['PNL133']
assert info['same_elevation_sources'] == {'PNL133': core.ELEVATION_BY_BAND}
def test_an_unmapped_group_on_both_sides_is_the_normal_case_geometry_answers():
"""No `elevation_group` anywhere -- the common state on a job with no
such parameter mapped -- and the geometric floor answers exactly as it
would have if the accelerator did not exist."""
shared = {'axis': 'X', 'min': 100.0, 'max': 100.667}
target = base('PNL425', elevation_band=shared)
donor = base('PNL133', elevation_band=shared)
sug, info = B.propose(target, [donor], donor_filter=PNL)
assert info['same_elevation_donors'] == ['PNL133']
assert info['same_elevation_sources'] == {'PNL133': core.ELEVATION_BY_BAND}
def test_group_on_only_one_side_falls_back_to_geometry():
shared = {'axis': 'X', 'min': 100.0, 'max': 100.667}
target = base('PNL425', elevation_group='E3.16', elevation_band=shared)
donor = base('PNL133', elevation_group=None, elevation_band=shared)
sug, info = B.propose(target, [donor], donor_filter=PNL)
assert info['same_elevation_donors'] == ['PNL133']
assert info['same_elevation_sources'] == {'PNL133': core.ELEVATION_BY_BAND}
# ----------------------------------------------------- the donor cap, plumbed
#
# The cap is the matcher's, and it is tested there. What has to be true HERE
# is that `propose` hands it down and reports it, because a cap the join
# silently drops is a cap that only exists in the unit tests.
def test_propose_declares_the_cap_it_ran_under():
target = piece('PNL640', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
donor = piece('PNL641', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
sug, info = B.propose(target, [donor], donor_filter=PNL)
assert info['donor_cap'] == 4
assert sug.donor_cap == 4
def test_the_shipped_cap_is_four():
"""The owner's number, asserted where it ships rather than trusted."""
assert match.DEFAULT_MAX_DONORS == 4
def test_propose_passes_the_cap_through_to_the_matcher():
"""Driven to 1 so the cap has to bite on a two-donor problem: the answer
is the better single donor plus a named gap, never a second donor."""
target = piece('PNL642', 30.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (20.0, 22.0, 2.0, 5.0)])
left = piece('PNL643', 30.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
right = piece('PNL644', 30.0, 10.0, 8.0, [(20.0, 22.0, 2.0, 5.0)])
two, _ = B.propose(target, [left, right], donor_filter=PNL)
assert len(two.best.donors) == 2
covered_by_two = two.best.covered_count
one, info = B.propose(target, [left, right], donor_filter=PNL,
max_donors=1)
assert info['donor_cap'] == 1
assert len(one.best.donors) == 1 # never a second donor
assert one.best.covered_count < covered_by_two
assert one.capped_out # and it says what it dropped
# The two kinds of gap stay apart: what the cap dropped is not what
# nobody has, whatever else this pair of donors could not reach.
assert not set(one.capped_out) & set(one.uncovered)
# ------------------------------------------------- the whole run, NO DOCUMENT
#
# `suggest_from_index` is `suggest_for_piece` with the cached target record in
# place of the live measurement, and it is the only thing standing between
# this feature and a Revit licence. What is asserted here is that it is the
# SAME run -- same filter, same covers, same info dict -- and that the two
# places it must say something different (where the target came from, and what
# a missing target means) really do say something different.
def _snapshot(pieces, built_at='2026-08-30 09:00:00', scope=None):
cache = core.new_cache('a model')
cache['built_at'] = built_at
cache['scope'] = scope
cache['pieces'] = dict((p['name'], p) for p in pieces)
return cache
def test_a_target_is_answered_straight_out_of_the_snapshot():
target = piece('PNL700', 30.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (20.0, 22.0, 2.0, 5.0)],
reinforced=0)
donor = piece('PNL701', 30.0, 10.0, 8.0,
[(4.0, 6.0, 2.0, 5.0), (20.0, 22.0, 2.0, 5.0)])
cache = _snapshot([target, donor])
sug, info = B.suggest_from_index(cache, 'PNL700')
assert sug is not None
assert info['offline'] is True
assert info['target_source'] == 'index'
assert info['built_at'] == '2026-08-30 09:00:00'
assert info['donor_names'] == ['PNL701']
assert sug.status == match.COMPLETE
def test_the_target_record_is_never_offered_as_its_own_donor_pool():
"""A not-yet-reinforced target sits in the same file as the donors now.
It may not donate to anybody, including to another target."""
a = piece('PNL702', 30.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)], reinforced=0)
b = piece('PNL703', 30.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)], reinforced=0)
sug, info = B.suggest_from_index(_snapshot([a, b]), 'PNL702')
assert info['donors'] == 0
assert sug.status == match.NO_DONORS
def test_a_missing_target_offline_is_not_the_same_as_missing_from_the_model():
"""With no model open nobody can say whether the piece exists."""
sug, info = B.suggest_from_index(_snapshot([]), 'PNL704')
assert sug is None
assert info['target_status'] == 'not_in_index'
assert info['offline'] is True
def test_the_same_call_from_the_live_path_still_says_not_in_model():
sug, info = B.suggest_from_index(_snapshot([]), 'PNL705', offline=False)
assert sug is None
assert info['target_status'] == 'not_in_model'
# -------------------------------------------------------- the scope, and D2
def _scope(prefixes):
from vibe import scope as scopelib
return scopelib.Scope(prefixes=prefixes)
def test_an_in_scope_target_is_never_annotated_as_out_of_scope():
"""Verified against a live run, 2026-08-30: the info dict carried
`target_in_scope: True` AND the "JUDGED OUTSIDE THE DECLARED SCOPE, AT
YOUR REQUEST" annotation at the same time, because the name was passed to
`Scope.annotation` unconditionally. A report that contradicts itself in
one dict teaches the reader to skip both lines."""
target = piece('PNL706', 30.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
reinforced=0)
donor = piece('PNL707', 30.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
_sug, info = B.suggest_from_index(_snapshot([target, donor]), 'PNL706',
the_scope=_scope(['PNL']))
assert info['scope']['target_in_scope'] is True
assert info['scope']['target_annotation'] is None
def test_an_out_of_scope_target_is_still_annotated():
"""The fix must not silence the case the annotation exists for."""
target = piece('BM708', 30.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
reinforced=0)
donor = piece('PNL709', 30.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
_sug, info = B.suggest_from_index(_snapshot([target, donor]), 'BM708',
the_scope=_scope(['PNL']))
assert info['scope']['target_in_scope'] is False
assert 'OUTSIDE THE DECLARED SCOPE' in info['scope']['target_annotation']
def test_the_scope_bounds_the_offline_donor_pool_the_same_way():
target = piece('PNL710', 30.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
reinforced=0)
mine = piece('PNL711', 30.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
theirs = piece('BM712', 30.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)])
_sug, info = B.suggest_from_index(_snapshot([target, mine, theirs]),
'PNL710', the_scope=_scope(['PNL']))
assert info['donor_names'] == ['PNL711']
assert info['rejected']['prefix'] == 1
# --------------------------------------------------------- the outline audit
def test_the_audit_is_read_by_folder_when_there_is_no_document(tmp_path):
import json
folder = str(tmp_path)
handle = open(os.path.join(folder, B.AUDIT_FILE), 'wb')
try:
handle.write(json.dumps({'approximate': ['PNL713']}).encode('utf-8'))
finally:
handle.close()
assert B.load_audit_at(folder) == set(['PNL713'])
def test_never_audited_stays_None_and_never_becomes_an_empty_set(tmp_path):
"""Never checked and checked-and-found-none are different answers."""
assert B.load_audit_at(str(tmp_path)) is None
def test_the_offline_run_reduces_designs_with_the_pattern_in_the_file():
"""`nomenclature.design_number_re` is plant knowledge and there is no
knowledge layer with no model open, so the index stamps it and this is
where it gets picked up. Without it, offline and the button could reduce
the same two numbers to different families -- and the whole point of the
family is deciding who may donate."""
target = piece('PNL950', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
reinforced=0, design='PNL1.0')
other = piece('PNL951', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
design='PNL2.0')
snap = _snapshot([target, other])
strict, info = B.suggest_from_index(snap, 'PNL950')
assert strict is None # PNL1 is not PNL2
assert info['design']['status'] == B.DESIGN_NONE_MATCH
# The same file, stamped with a pattern that stops at the letters: now
# they are one design and the donor is offered.
snap['nomenclature'] = {'design_number_re': r'^([A-Za-z]+)'}
loose, info = B.suggest_from_index(snap, 'PNL950')
assert info['donor_names'] == ['PNL951']
assert loose is not None
def test_an_index_with_no_stamped_pattern_falls_back_rather_than_refusing():
"""An index built before the stamp is not an index that cannot be read.
It falls back to the built-in pattern, which is what every other reader of
an unmapped nomenclature in this codebase already does."""
target = piece('PNL960', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
reinforced=0, design='PNL1.0')
donor = piece('PNL961', 20.0, 10.0, 8.0, [(4.0, 6.0, 2.0, 5.0)],
design='PNL1.A')
snap = _snapshot([target, donor])
del snap['nomenclature']
sug, info = B.suggest_from_index(snap, 'PNL960')
assert info['donor_names'] == ['PNL961']
assert sug is not None