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

History-free snapshot of the private development repository at cbe45c5
(2026-09-09). Code, docs and public catalogue only; no plant or job
knowledge layers, no client or job names (tools/scrub.py clean). The
intro deck is left out of this snapshot because its slide images could
not be checked for job drawings.
This commit is contained in:
2026-09-09 08:32:15 -05:00
commit 8e6ee31596
406 changed files with 223435 additions and 0 deletions
+128
View File
@@ -0,0 +1,128 @@
# -*- coding: utf-8 -*-
"""`tools/panelanalysis.py::build_analysis_page` -- the READ-ONLY results
page for the `panelanalysis/1` schema (2026-09, results-page redesign).
Guards the redesign's own hard rules, on two decks:
MINIMAL `schema.new_deck()` as-is -- two dunnage supports, two
straight strands, no in-place restraints/wind at all (the
Stage-0 default). Exercises the "not judged" path for
in-place strength/service.
IN-PLACE the same deck with lateral restraints and a manual wind zone
added, so the in-place strength/service models actually
solve and their own SVG envelope diagrams
(`panelanalysis._inplace_diagram`) render.
This does not repeat `test_panelanalysis_schema.py`'s coverage of the
engine/schema layer -- it only checks what the WRITTEN PAGE looks like:
- never an `<input>` or `<select>` (the input side lives in the 前端 now)
- never a DECK / NOT READ / COMPUTED badge (`CHIPS`' own vocabulary)
- the Summary card is present (`class="verdict"` + `class="stageboxes"`)
- no decimal-feet number anywhere (every length is feet-inches)
- the page is well under the ~1 MB budget and opens standalone (its own
`<style>` carries the embedded CSS -- no `<link rel="stylesheet">`)
Import pattern mirrors `test_panelanalysis_schema.py`: `tools/` on
`sys.path`, `deckcheck` imported first for its `vibe` stub side effect.
"""
import copy
import os
import re
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
TOOLS = os.path.abspath(os.path.join(HERE, os.pardir))
if TOOLS not in sys.path:
sys.path.insert(0, TOOLS)
import deckcheck # noqa: E402,F401 -- registers the `vibe` stub
import panelanalysis # noqa: E402
import panelanalysis_schema as schema # noqa: E402
DECIMAL_FT = re.compile(r'\d+\.\d+\s*ft\b')
def minimal_deck():
return schema.new_deck()
def in_place_deck():
"""`new_deck()`, wired for the in-place strength/service models to
solve: three lateral restraints (so `schema.restraints()` sees >= 2)
and one manual wind zone -- the same shape `WPA655.pa.json` (the deck
this redesign was built and screenshotted against) carries.
"""
deck = schema.new_deck(length_ft=37.5833, width_ft=8.375)
deck['structural_model']['restraints'] = [
{'x_ft': 2.0, 'type': 'Pin', 'gravity': True, 'thermal': False},
{'x_ft': 15.0, 'type': 'Floor tie', 'gravity': True,
'thermal': False},
{'x_ft': 22.0, 'type': 'Floor tie', 'gravity': True,
'thermal': False},
]
deck['loading']['wind'] = {
'mode': 'manual',
'zones': [{'label': 'W1', 'x0_ft': 0.0, 'x1_ft': deck[
'concrete_extents']['length_ft'], 'pressure_psf': 30.0,
'suction_psf': 35.0}],
}
return deck
def _check_common_invariants(html):
assert '<input' not in html
assert '<select' not in html
for badge in ('>DECK<', '>NOT READ<', '>COMPUTED<', '>SPEC<',
'>KNOWLEDGE<', '>PLANNED<', '>NOT COMPUTED<'):
assert badge not in html, badge
assert 'class="chip' not in html
assert '<link rel="stylesheet"' not in html
assert 'class="verdict"' in html
assert 'class="stageboxes"' in html
assert 'class="stagebox' in html
bad = DECIMAL_FT.findall(html)
assert not bad, 'decimal-feet numbers found: {0}'.format(bad)
assert len(html.encode('utf-8')) < 1024 * 1024
def test_minimal_deck_page_has_no_inputs_or_badges_and_a_summary_card():
html = panelanalysis.build_analysis_page(minimal_deck())
_check_common_invariants(html)
# Nothing wires the in-place model on this deck -- both its models are
# NOT JUDGED, named as such, never a fabricated zero.
assert 'not judged' in html.lower()
def test_in_place_deck_solves_and_draws_its_own_envelope_diagrams():
deck = in_place_deck()
html = panelanalysis.build_analysis_page(deck)
_check_common_invariants(html)
# The in-place models actually ran on this deck -- PASS/WARN/FAIL, not
# "not judged", for In-Place Strength and In-Place Service.
assert 'In-Place Strength' in html
assert 'In-Place Service' in html
# This file's own SVG diagrams for the governing in-place combination
# (`panelanalysis._inplace_diagram`) rendered -- their titles are
# unique to them (the handling stages' reused `R.diagram_plot` figures
# never say "governing combination").
assert 'governing combination' in html.lower()
def test_handling_stages_each_get_their_own_section_and_tag():
html = panelanalysis.build_analysis_page(minimal_deck())
for stage in ('Stripping', 'Transportation', 'Erection'):
assert 'Handling — {0}'.format(stage) in html or \
'Handling &mdash; {0}'.format(stage) in html
def test_page_is_deterministic_given_the_same_deck_modulo_timestamp():
"""Two builds a second apart differ only in the 'generated HH:MM' line
-- nothing else on a read-only report should vary run to run."""
deck = in_place_deck()
h1 = panelanalysis.build_analysis_page(copy.deepcopy(deck))
h2 = panelanalysis.build_analysis_page(copy.deepcopy(deck))
strip = lambda s: re.sub(r'generated \d{4}-\d\d-\d\d \d\d:\d\d',
'generated X', s)
assert strip(h1) == strip(h2)