WillTools 2026-09-09 -- clean snapshot of the development repo for review
ci / test (push) Successful in 6m14s

History-free snapshot of the private development repository at 77a82eb.
Code, docs and the public catalogue only: no plant or job knowledge
layers, no client, job or producer names (tools/scrub.py clean against
the widened term list; a second word-level grep clean). The intro deck is
left out because its slide images cannot be checked for job drawings.
This commit is contained in:
2026-09-09 08:35:15 -05:00
commit 25592fa6c2
406 changed files with 223435 additions and 0 deletions
@@ -0,0 +1,357 @@
# -*- coding: utf-8 -*-
"""Pins the instance-then-type fallback in `ticketqc.pstr` / `pdouble`.
THE DEFECT THIS GUARDS AGAINST
--------------------------------
`Element.LookupParameter` only ever sees parameters that live on the
INSTANCE. A knowledge role the plant layer maps to a TYPE parameter (wall
thickness is the standing example) therefore read back `None` forever, and
silently -- a role reading `None` just means the check stands down, so the
report still rendered and the checklist still printed with nothing to show
it had skipped anything. Verified live 2026-09-02 against a real 8" wall
panel: the thickness role read `None` off the instance and "8"" off the
type.
`pstr`/`pdouble` now read the instance first (an instance override, even an
unusual one, is what this particular piece actually carries) and fall back
to the type only when the instance has nothing -- no such parameter, or one
that is present but blank.
WHAT IS PINNED HERE, why each case matters
--------------------------------------------
1. Value only on the type -- the whole point of the fix. Must now resolve.
2. Value on both -- instance must win. This is the precedence rule, not
an accident of "whichever is checked first."
3. A fake with no type reachable at all (no `GetTypeId`) -- must behave
EXACTLY as before: return the instance's raw answer, never raise. This
is what keeps every existing fake element in the rest of the suite
from suddenly needing Revit-shaped attributes it never had.
4. A type lookup that raises (a `Document.GetElement` that blows up) --
must degrade to the instance answer, not propagate. Revit can hand
back all manner of half-built objects mid-edit; this function may
never be the thing that turns that into an unhandled exception.
`pdouble` gets the identical fallback (case 1) for the identical reason --
same defect, same fix -- but NOT the "instance wins on a tie" case, because
0.0 is a legitimate instance value and this file does not want to relitigate
`pdouble`'s own units warning about AsDouble(); its docstring already covers
that ground and weight/unit-weight roles are read through `pstr`, not this.
"""
# pylint: disable=import-error,invalid-name,broad-except
import sys
import types
import pytest
def _stub_revit():
"""`Autodesk.Revit.DB`, inert, for a host interpreter.
Same shape as `test_ticketqc_evidence.py`'s stub, with `StorageType`
given real `.String` / `.Double` sentinels -- `pstr`/`pdouble` branch on
those, so an empty placeholder class would make every read fall through
the wrong arm rather than exercising the fallback under test.
"""
if 'Autodesk.Revit.DB' in sys.modules:
return []
autodesk = types.ModuleType('Autodesk')
revit = types.ModuleType('Autodesk.Revit')
db = types.ModuleType('Autodesk.Revit.DB')
for name in ('FilteredElementCollector', 'AssemblyInstance', 'View',
'ViewSheet', 'ViewType', 'BuiltInCategory', 'Element',
'ElementId', 'XYZ', 'Transform',
'Options', 'Solid', 'BoundingBoxXYZ'):
setattr(db, name, type(str(name), (object,), {}))
class StorageType(object):
String = 'String'
Double = 'Double'
db.StorageType = StorageType
autodesk.Revit = revit
revit.DB = db
sys.modules['Autodesk'] = autodesk
sys.modules['Autodesk.Revit'] = revit
sys.modules['Autodesk.Revit.DB'] = db
return ['Autodesk.Revit.DB', 'Autodesk.Revit', 'Autodesk']
_ADDED = _stub_revit()
try:
from vibe import ticketqc as QC # noqa: E402
finally:
for _name in _ADDED:
sys.modules.pop(_name, None)
# `vibe.ticketqc` is cached in `sys.modules` process-wide, so if some OTHER
# test file imported it first through its own bare `StorageType` stub (no
# `.String` / `.Double`), `QC.StorageType` here is that same class object,
# not the one `_stub_revit` above just built. Stamp the two sentinels onto
# whichever `StorageType` class the module actually holds, rather than
# trusting that this file's stub is the one that won the import race.
QC.StorageType.String = 'String'
QC.StorageType.Double = 'Double'
# --------------------------------------------------------------- fake model
#
# Deliberately NOT built on any shared base class with the rest of the
# suite's fakes -- case 3 below needs an element that plainly has no
# `GetTypeId`, and a base class is exactly the thing that would quietly
# hand it one.
class Param(object):
def __init__(self, storage, string_value=None, double_value=None):
self.StorageType = storage
self._string_value = string_value
self._double_value = double_value
def AsString(self):
return self._string_value
def AsValueString(self):
return self._string_value
def AsDouble(self):
return self._double_value
def str_param(value):
return Param(QC.StorageType.String, string_value=value)
def double_param(value):
return Param(QC.StorageType.Double, double_value=value)
class FakeType(object):
"""Stands in for the `ElementType` `Document.GetElement` hands back."""
def __init__(self, params):
self._params = params or {}
def LookupParameter(self, name):
return self._params.get(name)
class FakeDoc(object):
def __init__(self, type_id, type_obj, raise_on_get=False):
self._type_id = type_id
self._type_obj = type_obj
self._raise_on_get = raise_on_get
def GetElement(self, type_id):
if self._raise_on_get:
raise RuntimeError('boom -- GetElement blew up')
if type_id != self._type_id:
return None
return self._type_obj
class InstanceOnly(object):
"""No `GetTypeId` at all -- the shape of every fake element already in
this suite before this change. Must not start raising."""
def __init__(self, params=None):
self._params = params or {}
def LookupParameter(self, name):
return self._params.get(name)
class WithType(InstanceOnly):
"""An instance whose type is reachable through `GetTypeId`/`Document`."""
def __init__(self, params=None, type_params=None, type_id='TYPE-1',
raise_on_get=False):
InstanceOnly.__init__(self, params)
self._type_id = type_id
self.Document = FakeDoc(type_id, FakeType(type_params),
raise_on_get=raise_on_get)
def GetTypeId(self):
return self._type_id
class TypeIdRaises(InstanceOnly):
"""`GetTypeId` itself blows up -- must degrade like `InstanceOnly`."""
def GetTypeId(self):
raise RuntimeError('boom -- GetTypeId blew up')
# --------------------------------------------------------------------- pstr
def test_value_only_on_the_type_is_now_found():
el = WithType(params={}, type_params={'Thickness': str_param('8"')})
assert QC.pstr(el, 'Thickness') == '8"'
def test_value_on_both_prefers_the_instance():
el = WithType(params={'Thickness': str_param('9"')},
type_params={'Thickness': str_param('8"')})
assert QC.pstr(el, 'Thickness') == '9"'
def test_no_type_reachable_behaves_exactly_as_before():
el = InstanceOnly(params={})
assert QC.pstr(el, 'Thickness') is None
el2 = InstanceOnly(params={'Mark': str_param('WP101')})
assert QC.pstr(el2, 'Mark') == 'WP101'
def test_get_type_id_raising_degrades_to_the_instance_answer():
el = TypeIdRaises(params={})
assert QC.pstr(el, 'Thickness') is None
el2 = TypeIdRaises(params={'Mark': str_param('WP101')})
assert QC.pstr(el2, 'Mark') == 'WP101'
def test_type_lookup_that_raises_degrades_to_the_instance_answer():
el = WithType(params={}, type_params={'Thickness': str_param('8"')},
raise_on_get=True)
assert QC.pstr(el, 'Thickness') is None
el2 = WithType(params={'Mark': str_param('WP101')},
type_params={'Mark': str_param('WP999')},
raise_on_get=True)
assert QC.pstr(el2, 'Mark') == 'WP101'
def test_instance_parameter_present_but_blank_still_falls_back_to_type():
el = WithType(params={'Thickness': str_param('')},
type_params={'Thickness': str_param('8"')})
assert QC.pstr(el, 'Thickness') == '8"'
def test_neither_instance_nor_type_has_it_is_none():
el = WithType(params={}, type_params={})
assert QC.pstr(el, 'Thickness') is None
def test_none_element_is_none():
assert QC.pstr(None, 'Thickness') is None
# ------------------------------------------------------------------ pdouble
def test_pdouble_value_only_on_the_type_is_now_found():
el = WithType(params={}, type_params={'Width': double_param(0.667)})
assert QC.pdouble(el, 'Width') == 0.667
def test_pdouble_value_on_both_prefers_the_instance():
el = WithType(params={'Width': double_param(0.5)},
type_params={'Width': double_param(0.667)})
assert QC.pdouble(el, 'Width') == 0.5
def test_pdouble_zero_on_instance_is_not_treated_as_missing():
# 0.0 is a legitimate instance value -- it must NOT fall through to the
# type just because it is falsy.
el = WithType(params={'Width': double_param(0.0)},
type_params={'Width': double_param(0.667)})
assert QC.pdouble(el, 'Width') == 0.0
def test_pdouble_no_type_reachable_behaves_exactly_as_before():
el = InstanceOnly(params={})
assert QC.pdouble(el, 'Width') is None
el2 = InstanceOnly(params={'Width': double_param(0.667)})
assert QC.pdouble(el2, 'Width') == 0.667
def test_pdouble_get_type_id_raising_degrades_to_the_instance_answer():
el = TypeIdRaises(params={})
assert QC.pdouble(el, 'Width') is None
def test_pdouble_type_lookup_that_raises_degrades_to_the_instance_answer():
el = WithType(params={}, type_params={'Width': double_param(0.667)},
raise_on_get=True)
assert QC.pdouble(el, 'Width') is None
# ----------------------------------------------------------- rstr unchanged
#
# `rstr` needs no change if the layer beneath it is fixed -- it just loops
# `pstr` over the role's candidate names. Confirmed rather than assumed: it
# now resolves a role mapped to a type-only parameter, with no edit to
# `rstr` itself.
class _FakeKnowledge(object):
"""The minimal shape `rstr` needs: `K.param_names(know, role)`."""
def test_rstr_resolves_a_role_mapped_to_a_type_only_parameter(monkeypatch):
from vibe import knowledge as K
monkeypatch.setattr(K, 'param_names',
lambda know, role: ['Thickness'])
el = WithType(params={}, type_params={'Thickness': str_param('8"')})
assert QC.rstr(el, _FakeKnowledge(), 'panel.thickness') == '8"'
# ---------------------------------------------------- instance-only / type-only
#
# `pstr_instance_only` / `pstr_type_only` (and their `rstr_*` twins) exist for
# exactly one caller, `ticketchecks._reinforcing_values`, which must keep an
# instance read and a type read genuinely mutually exclusive -- see that
# function's docstring. Pinned here so a future edit to `pstr`'s union does
# not quietly change these too.
def test_pstr_instance_only_never_sees_the_type():
el = WithType(params={}, type_params={'Thickness': str_param('8"')})
assert QC.pstr_instance_only(el, 'Thickness') is None
def test_pstr_instance_only_returns_the_instance_value_when_present():
el = WithType(params={'Thickness': str_param('9"')},
type_params={'Thickness': str_param('8"')})
assert QC.pstr_instance_only(el, 'Thickness') == '9"'
def test_pstr_instance_only_none_element_is_none():
assert QC.pstr_instance_only(None, 'Thickness') is None
def test_pstr_type_only_never_sees_the_instance():
el = WithType(params={'Thickness': str_param('9"')},
type_params={'Thickness': str_param('8"')})
assert QC.pstr_type_only(el, 'Thickness') == '8"'
def test_pstr_type_only_none_when_no_type_reachable():
el = InstanceOnly(params={'Thickness': str_param('9"')})
assert QC.pstr_type_only(el, 'Thickness') is None
def test_pstr_type_only_none_element_is_none():
assert QC.pstr_type_only(None, 'Thickness') is None
def test_rstr_instance_only_does_not_fall_back_to_the_type(monkeypatch):
from vibe import knowledge as K
monkeypatch.setattr(K, 'param_names',
lambda know, role: ['Thickness'])
el = WithType(params={}, type_params={'Thickness': str_param('8"')})
assert QC.rstr_instance_only(el, _FakeKnowledge(), 'panel.thickness') is None
el2 = WithType(params={'Thickness': str_param('9"')},
type_params={'Thickness': str_param('8"')})
assert QC.rstr_instance_only(el2, _FakeKnowledge(),
'panel.thickness') == '9"'
def test_rstr_type_only_does_not_fall_back_to_the_instance(monkeypatch):
from vibe import knowledge as K
monkeypatch.setattr(K, 'param_names',
lambda know, role: ['Thickness'])
el = WithType(params={'Thickness': str_param('9"')},
type_params={'Thickness': str_param('8"')})
assert QC.rstr_type_only(el, _FakeKnowledge(), 'panel.thickness') == '8"'
el2 = InstanceOnly(params={'Thickness': str_param('9"')})
assert QC.rstr_type_only(el2, _FakeKnowledge(), 'panel.thickness') is None