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,133 @@
# -*- coding: utf-8 -*-
"""The panelanalysis/1 In-Place SERVICE section (docs sec.6) + the P-Delta note.
Host CPython, loaded exactly like its siblings: reaches the tool through
`tools/` with the `vibe` stub in place. A wired deck (restraints + wind +
service inputs) must render the In-Place Service Summary -- tension/cracking,
compression, deflection -- and the strength section must carry the P-Delta
(2nd-order) magnifier. The could-not-judge discipline is enforced: a deflection
with no L/n limit is NOT JUDGED, named, never a fabricated pass; nothing on the
page is CJK; nothing is a traceback.
Everything written at runtime goes under tmp_path.
"""
from __future__ import annotations
import io
import json
import os
import re
import sys
import pytest
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(
os.path.abspath(__file__))))
TOOLS = os.path.join(ROOT, 'tools')
PANELLIFT_SRC = os.path.join(ROOT, 'panellift', 'src')
for p in (TOOLS, PANELLIFT_SRC):
if p not in sys.path:
sys.path.insert(0, p)
from vibe import knowledge # noqa: E402,F401 (registers the vibe stub)
from vibe import plantpath # noqa: E402,F401
pa = pytest.importorskip('panelanalysis')
schema = pytest.importorskip('panelanalysis_schema')
CJK = re.compile(u'[一-鿿]')
def _wired_deck(deflection_limit_ratio=150.0, wind=True, class_t=False):
"""A mild solid wall pinned top and bottom, with a service wind pressure."""
deck = schema.new_deck(length_ft=30.0, width_ft=10.0, thickness_in=12.0,
fc_psi=6000.0, strands=[])
deck['structural_model']['restraints'] = [
{'x_ft': 0.0, 'type': 'pin'}, {'x_ft': 30.0, 'type': 'pin'}]
if wind:
deck['loading']['wind'] = {'zones': [
{'x0_ft': 0.0, 'x1_ft': 30.0, 'pressure_psf': 50.0, 'label': 'W1'}]}
svc = {}
if deflection_limit_ratio is not None:
svc['deflection_limit_ratio'] = deflection_limit_ratio
if class_t:
svc['cracking_class_t'] = True
if svc:
deck['loading']['service'] = svc
return deck
# ------------------------------------------------------------ the run itself
def test_wired_deck_produces_a_service_result():
deck = _wired_deck()
panel = schema.to_panel(deck)
result, reason = pa.solve_in_place(deck, panel)
assert reason is None and result is not None and not result.refusal
svc = result.service
assert svc is not None and svc.stations
# a wind-loaded wall develops real service tension and compression
assert svc.max_tension_psi > 0.0
assert svc.max_compression_psi > 0.0
# cracking limit is the Class U 7.5 sqrt(6000) = 580.9 psi
assert abs(svc.stations[0].cracking_limit_psi - 580.9) < 0.5
# deflection judged against L/150 = 2.4 in
d = svc.deflection
assert d.combo == 'SC5' and d.util is not None
assert abs(d.limit_in - 30.0 * 12.0 / 150.0) < 1e-6
def test_class_t_deck_raises_the_cracking_limit():
deck = _wired_deck(class_t=True)
panel = schema.to_panel(deck)
result, _reason = pa.solve_in_place(deck, panel)
import math
assert abs(result.service.stations[0].cracking_limit_psi
- 12.0 * math.sqrt(6000.0)) < 0.5
# ------------------------------------------------------------- the rendering
def test_page_renders_the_service_summary_and_pdelta():
deck = _wired_deck()
html = pa.build_analysis_page(deck)
assert '>In-Place Service Summary<' in html
for needle in ('Tension vs cracking', 'Total compression', 'Deflection',
'Cracking (psi)', 'Combination'):
assert needle in html, needle
# the P-Delta 2nd-order magnifier appears in the strength section
assert 'P-&Delta; (2nd-order' in html
assert 'magnifier' in html
assert 'Traceback' not in html
m = CJK.search(html)
assert not m, 'CJK: {0!r}'.format(m.group() if m else '')
def test_deflection_without_limit_is_not_judged_not_faked():
deck = _wired_deck(deflection_limit_ratio=None)
html = pa.build_analysis_page(deck)
assert '>In-Place Service Summary<' in html
# the deflection is computed, but the LIMIT check is named NOT JUDGED
assert 'Deflection limit NOT' in html or 'NOT JUDGED' in html
result, _r = pa.solve_in_place(deck, schema.to_panel(deck))
assert result.service.deflection.util is None
assert result.service.deflection.why
def test_unwired_deck_keeps_the_explicit_service_placeholder():
deck = schema.new_deck(support_xs=(2.0, 22.0)) # no restraints
html = pa.build_analysis_page(deck)
assert '>In-Place Service (not computed)<' in html
assert 'Traceback' not in html
def test_cli_end_to_end_renders_service_under_tmp_path(tmp_path):
deck = _wired_deck()
deck_path = tmp_path / 'PNL101.pa.json'
out_path = tmp_path / 'out.html'
with io.open(str(deck_path), 'w', encoding='utf-8') as fh:
json.dump(deck, fh)
rc = pa.main([str(deck_path), '-o', str(out_path)])
assert rc == 0 and out_path.exists()
html = out_path.read_text(encoding='utf-8')
assert 'In-Place Service Summary' in html