# -*- coding: utf-8 -*- """Which end of the piece is up, when it came from a fallback -- and the red line telling the reader to go check TOT on the model. `report.up_end_disclosure()` / `report._up_end_block()` already print the fallback's own explanation, unconditionally, whenever `source.up_end_basis` is anything but the ruled mechanism (`RULED_UP_END_BASIS`). What is new here is `report._up_end_is_origin_defect()`: of the three reasons the ruled mechanism can decline (see `up_end_from_origin()` in `WillTools.extension/lib/vibe/knowledge.py`), only the FIRST -- the origin's own up vector does not point up -- is a defect on the assembly's origin itself. The other two (near-square; not yet confirmed for this piece's orientation) are gaps in what the rule covers, not something wrong with the model, and must never carry the same red call to action. """ import re from conftest import make_panel from panellift import report # Verbatim from `up_end_from_origin()`'s FIRST refusal # (WillTools.extension/lib/vibe/knowledge.py) -- the exact shape # `liftexport` writes into `source.up_end_basis_why`, and the real text on # WP401 (2026-09-01). ORIGIN_NOT_UP_WHY = ( "The origin of assembly WP401 does not stand the piece up: its up " "basis is (0.0, 1.0, 0.0) rather than world up. One assembly in 282 is " "like this -- its face normal points up instead -- and on such a " "piece every reading off the frame is wrong, so nothing is read off " "this one. Which end is up was therefore read from GLOBAL ELEVATION " "instead -- the end of the piece that is higher in the model. That is " "a fallback, not the rule.") # Verbatim shape of the SECOND refusal (near square) -- must NOT flag. NEAR_SQUARE_WHY = ( "Assembly PNL127 is near square (11.63 x 11.58 ft, ratio 1.00), and " "below 1.25 the long direction cannot be told from the up direction.") # Verbatim shape of the THIRD refusal (not yet confirmed for this # orientation) -- must NOT flag either; this is a coverage gap, not a # defect on the model. Matches `up_end_from_origin()`'s wording as fixed # 2026-09-01: green (BasisY/world-up) is now confirmed for a vertical wall # panel too, so the message no longer claims nobody has said how vertical # panels work -- only that this function has not been extended to run # there, which is a coverage gap and NOT a defect on the origin. NOT_HORIZONTAL_WHY = ( "The origin rule is confirmed for HORIZONTAL panels only, and the " "origin of assembly PNL1 stands its length up, which is not one. The " "owner has confirmed the same green-arrow reading also holds on a " "vertical wall panel (2026-09-01), but this rule has not been " "extended to run there yet, so the origin is not read on this piece.") def _panel_with_fallback(why, basis='global elevation'): panel = make_panel() panel.source = { 'up_end_basis': basis, 'up_end_basis_why': why, 'up_end_affects': 'erection -- which row of face lifters the crane ' 'cannot reach, and which edge the anchors are on', } return panel # ------------------------------------------------- _up_end_is_origin_defect def test_the_origin_not_up_refusal_is_flagged(): assert report._up_end_is_origin_defect(ORIGIN_NOT_UP_WHY) is True def test_the_near_square_refusal_is_not_flagged(): assert report._up_end_is_origin_defect(NEAR_SQUARE_WHY) is False def test_the_not_yet_confirmed_orientation_refusal_is_not_flagged(): assert report._up_end_is_origin_defect(NOT_HORIZONTAL_WHY) is False def test_empty_or_none_why_is_not_flagged(): assert report._up_end_is_origin_defect('') is False assert report._up_end_is_origin_defect(None) is False # --------------------------------------------------------- _up_end_block() def test_the_red_line_appears_when_the_origin_itself_is_wrong(): """WP401's real shape: the origin does not point up at all, so this is a defect on the assembly's own TOT, not a caveat about the analysis.""" panel = _panel_with_fallback(ORIGIN_NOT_UP_WHY) block = report._up_end_block(panel) assert 'tot-flag' in block assert 'TOT' in block # The short fact is always visible; the measured reasoning ("does not # stand the piece up") is inside the fold, not repeated at top level. assert 'read from global elevation, not the assembly origin' in block assert 'does not stand the piece up' in block def test_the_block_is_short_a_few_lines_not_a_wall_of_text(): """The owner's own words, 2026-09-01: '把这一段从lift的结果里面删掉, 或者缩短...太长了压根不会看的' -- delete this section or shorten it, it is so long nobody will read it at all. The block he cut was ~700 characters; the always-visible text (outside the fold) must be a small fraction of that.""" panel = _panel_with_fallback(ORIGIN_NOT_UP_WHY) block = report._up_end_block(panel) # Everything inside the fold is closed by default and does not count # against "what a reader sees at a glance" -- strip it out before # measuring, the same way a browser would hide it on load. Tags do not # count either: they are never visible text, only the characters # between them are. fold_start = block.index('') + len('') always_visible = block[:fold_start] + block[fold_end:] visible_text = re.sub(r'<[^>]+>', '', always_visible) assert len(visible_text) < 250, (len(visible_text), visible_text) def test_fallback_not_the_rule_appears_at_most_once(): """The old block said this exact clause TWICE in one paragraph -- once as the report's own intro sentence, once again from the end of the producer string it quoted. That repetition, not the length alone, was what the owner named as the reason he stopped reading.""" panel = _panel_with_fallback(ORIGIN_NOT_UP_WHY) block = report._up_end_block(panel) assert block.count('fallback, not the rule') <= 1 def test_the_full_reasoning_is_folded_using_the_report_s_own_mechanism(): """Not deleted, not moved to a different wall of visible text -- folded behind the SAME
/_sec() idiom every other section already uses, closed by default.""" panel = _panel_with_fallback(ORIGIN_NOT_UP_WHY) block = report._up_end_block(panel) assert '
' in block assert 'Why' in block assert 'open' not in block.split('')[0] # The full producer reasoning is still there -- just inside the fold. assert 'One assembly in 282' in block assert 'That is a fallback, not the rule.' in block def test_the_red_line_is_absent_for_the_near_square_refusal(): """A near-square piece is genuinely undecidable, not a broken origin -- the red 'go check TOT' line would send the reader to fix a model that is not wrong.""" panel = _panel_with_fallback(NEAR_SQUARE_WHY) block = report._up_end_block(panel) assert block # the disclosure itself still prints assert 'tot-flag' not in block assert 'TOT' not in block def test_the_red_line_is_absent_for_the_not_yet_confirmed_orientation(): """A vertical panel the rule has not been extended to cover yet is a known gap, not a defect -- same non-flag as the near-square case.""" panel = _panel_with_fallback(NOT_HORIZONTAL_WHY) block = report._up_end_block(panel) assert block assert 'tot-flag' not in block assert 'TOT' not in block def test_no_block_at_all_when_the_ruled_mechanism_answered(): """`up_end_basis` == the ruled mechanism (`RULED_UP_END_BASIS`) means there is nothing to disclose -- and therefore nothing to flag.""" panel = _panel_with_fallback('assembly origin should never get here', basis=report.RULED_UP_END_BASIS) assert report._up_end_block(panel) == '' def test_no_block_at_all_when_the_panel_has_no_source_disclosure(): panel = make_panel() panel.source = {} assert report._up_end_block(panel) == '' def test_the_flag_uses_the_same_red_every_fail_on_the_page_already_uses(): """Match the report's existing severity styling rather than inventing a new colour -- var(--fail), the same variable `.FAIL` uses.""" assert '.tot-flag{color:var(--fail)' in report.CSS def test_the_flag_is_small_text_not_a_banner(): """It sits inside the existing warn-styled .upend box; it must not carry its own background, border or oversized font that would read as a second banner on the page.""" css = report.CSS start = css.index('.tot-flag{') end = css.index('}', start) rule = css[start:end] assert 'font-size:12px' in rule assert 'background' not in rule assert 'border' not in rule