== A. every CAS template through desktop Giac 1.9, against Python fractions ==
   (icas: // (c) 2001, 2021 B. Parisse & others)
PASS A1 bt_Rat: decimals as n/10^d, count ratios recovered exactly (92/95, 7/9, 2/3)   []
PASS A1 bt_Rat: a value with more than 6 decimals is rounded and flagged (kind 2)   [123457, 1000000, 2]
PASS A2 1188 CAS texts (PPV, NPV, 1 - PPV, break-even; 1 and 2 tests): Giac = Python fractions   []
PASS A2 no CAS text holds a decimal point (BRIEF_CAS rule 1)   []
PASS A3 ppv(prior 0.01, 0.95 / 0.95) = 19/118   19/118
PASS A3 npv(prior 0.01, 0.95 / 0.95) = 1881/1882   1881/1882
PASS A3 be(prior 0.01, 0.95 / 0.95) = 1/20   1/20
PASS A3 ppv(prior 0.1, 0.9 / 0.95) = 2/3   2/3
PASS A3 ppv(prior 0.1, 0.9 / 0.95, 2 tests) = 36/37   36/37
PASS A3 be(prior 0.1, 0.9 / 0.95, 2 tests) = 1/325   1/325
PASS A3 ppv(prior 0.05, 0.9 / 0.968421) = 3/5   3/5
PASS A3 comp(prior 0.1, 0.9 / 0.95) = 1/3   1/3
PASS A3 natural frequencies at N = 10000: TP 95, FP 495, PPV 95/590 = 19/118 = 0.161
PASS A4 8a: the solves arrive in the Prime's braces ({(-btc+1)/(-btc+bts+1)}, {1/(btl*btm+1)}), which bt_Strip drops
PASS A4 symbolic break-even, 1 test: Giac (-btc+1)/(-btc+bts+1) = SymPy (1 - btc)/(-btc + bts + 1)
PASS A4 symbolic break-even, 2 tests: Giac 1/(btl*btm+1) = SymPy 1/(btl*btm + 1)
PASS A4 the solve is linear in the prior: exactly one root, so the Strip step needs no choice
PASS A5 bt_BEp (PPL, draws the mark) = the CAS break-even, every test and both chains   max diff 6.9e-17

== B. the program in the harness (ppl_run_v3d), cas = giac and cas = fail ==
PASS B1 defaults: panel PPV = 2/3, NPV = 171/173, badge exact (CAS)   ['PPV = 2/3', 'NPV = 171/173', 'exact (CAS), tap', 'Most T+ are false', 'if prior < 5.3 %']
PASS B1 defaults: break-even lines "Most T+ are false / if prior < 5.3 %" (1/19)   ['Most T+ are false', 'if prior < 5.3 %']
PASS B1 defaults: the CAS was asked 3 times for the first frame (PPV, NPV, break-even)   ['string((1/10*9/10)/(1/10*9/10+9/10*5/100))', 'string((9/10*95/100)/(9/10*95/100+1/10*1/10))', 'string(solve((btq*9/10)/(btq*9/10+(1-btq)*5/100)=1/2,btq))']
PASS B1 summary on exit carries the exact PPV   BayesTree: PPV = 0.667 = 2/3, NPV = 0.988 (prior 0.100, sens 0.900, spec 0.950)
PASS B1 8a: every CAS text asks for string(...), every answer arrives quoted; no CAS variable assigned, no CAS call of a variable   [('string((1/10*9/10)/(1/10*9/10+9/10*5/100))', '"2/3"', 62.81423568725586)]
PASS B1 break-even mark: magenta line above the track at x = 214 (bt_SlX(1/19)), red tint left of it   1 mark, 1 tint
PASS B1 layout: no tree text reaches the soft keys (y >= 218) or x 318   []
PASS B2 example tree panel: PPV = 19/118, NPV = 1881/1882   ['PPV = 19/118', 'NPV = 1881/1882', 'exact (CAS), tap', 'Most T+ are false', 'if prior < 5.0 %']
PASS B2 Exact page 1 shows "Picture N = 10000 people (natural frequencies):"
PASS B2 Exact page 1 shows "TP = 95, FP = 495, FN = 5, TN = 9405"
PASS B2 Exact page 1 shows "PPV = TP/(TP+FP) = 95/590"
PASS B2 Exact page 1 shows "= 19/118 = 0.161"
PASS B2 Exact page 1 shows "= 1881/1882 = 0.999"
PASS B2 Exact page 1 shows "prior = 1/20 = 0.0500 = 5.0 %"
PASS B2 Exact page 1 shows "Below a prior of 5.0 %, a positive result is more"
PASS B2 Exact page 2 shows "PPV = TP/(TP+FP) = p×se / (p×se + (1−p)×(1−sp))"
PASS B2 Exact page 2 shows "= 0.01×0.95 / (0.01×0.95 + 0.99×0.05)"
PASS B2 Exact page 2 shows "p = (-sp+1)/(-sp+se+1)"
PASS B2 Exact page 2 shows "your numbers: p = 1/20 = 0.0500"
PASS B2 both pages carry the badge "exact (CAS)"
PASS B2 layout: no Exact-page line past x 318 (estimated widths)   []
PASS B2 opening the page asked the CAS once more (the symbolic solve), the rest was cached   ['frac', 'frac', 'solve', 'solve']
PASS B3 slider drag: every drag frame says "exact: on lift" (no stale fraction shown)   ['exact: on lift', 'exact: on lift', 'exact: on lift', 'exact: on lift', 'exact: on lift']
PASS B3 slider drag: CAS asked 3 times at the start and 2 times after the lift (PPV, NPV) -- no solve   ['frac', 'frac', 'solve', 'frac', 'frac']
PASS B3 slider drag: the break-even lines stay put through the drag (they do not depend on the prior)   {'if prior < 5.3 %'}
PASS B3 8b: slider drag: the four leaves re-count in every frame, the lift frame too, each pair adding up (7 frames)   []
PASS B3 slider drag: exactly one extra frame after the lift (the CAS update), same prior as the last sample   7 frames
PASS B3 after the lift the panel shows the exact PPV for the new prior (0.001): PPV = 2/113   ['PPV = 2/113', 'NPV = 18981/18983', 'exact (CAS), tap', 'Most T+ are false', 'if prior < 5.3 %']
PASS B4 sens drag: the break-even mark moves in the drag frame, before the lift (PPL), [214.0, 215.0, 215.0]
PASS B4 sens drag: CAS asked 3 times at the start, then 3 after the lift (PPV, NPV, solve)   ['frac', 'frac', 'solve', 'frac', 'frac', 'solve']
PASS B5 a key (Right, spec 0.96): one update of 3 CAS calls, then the panel is exact   6 calls, ['PPV = 5/7', 'NPV = 432/437', 'exact (CAS), tap', 'Most T+ are false', 'if prior < 4.3 %']
PASS B5 back to a value seen before still asks again (one cache, by design): 9 calls   9
PASS B5 tapping a box and closing its page: no new CAS call (inputs unchanged)   3
PASS B6 forensic panel: PPV = 2/3, 1−PPV = 1/3, "Most matches false / below 1 in 19"   ['PPV = 2/3', '1−PPV = 1/3', 'exact (CAS), tap', 'Most matches false', 'below 1 in 19']
PASS B7 two tests panel: PPV = 36/37 (= 0.972973), NPV = 19/23, "Most T+T+ false / if prior < 0.31 %"   ['PPV = 36/37', 'NPV = 19/23', 'exact (CAS), tap', 'Most T+T+ false', 'if prior < 0.31 %']
PASS B7 two tests Exact page: N = 100000, 13500 positive on test 1, prior = 1/325
PASS B7 two tests page 2: the CAS solve in LR form, p = 1/(LR₁×LR₂+1)
PASS B7 two tests: the slider mark sits at the base prior 1/325 (x = 185)
PASS B8 Enter counts 45/5/30/920: PPV = 3/5 (= 45/75), NPV = 184/185 (= 920/925)   ['PPV = 3/5', 'NPV = 184/185', 'exact (CAS), tap', 'Most T+ are false', 'if prior < 3.4 %']
PASS B9 a tap on the exact panel opens the Exact page
PASS B10 soft key page 3, slot 5 "Exact" opens the Exact page
PASS B11 PPV view: magenta square at the crossing (x 53, y 107)
PASS B11 PPV view: "Below 5.3 %, most positives are false (PPV < 1/2)."
PASS B11 PPV view layout: tick labels at y 189, the sentence at y 199, readout 212, footer 226   [189.0, 199.0, 212.0, 226.0]
PASS B12 cas=fail: no runtime error, the program ends normally   None
PASS B12 cas=fail: tree panel shows the decimals and "decimal, tap"   ['PPV = 0.161', 'NPV = 0.999', 'decimal, tap', 'Most T+ are false', 'if prior < 5.0 %']
PASS B12 cas=fail: Exact pages say "decimal", keep the natural-frequency fraction 95/590 (PPL counts)
PASS B12 cas=fail: page 2 gives the break-even by hand and says no CAS answer
PASS B12 cas=fail: the summary has no fraction   BayesTree: PPV = 0.161, NPV = 0.999 (prior 0.010, sens 0.950, spec 0.950)
PASS B12 8c: beta 8b in harness v3d STOPS on the same cas=fail run (INSTRING: Invalid input (the first argument is an empty string -- emulator, 17 O)
PASS B13 slow CAS: after the first update the tree says "tap for exact" and asks no more   ['tap for exact', 'Most T+ are false', 'if prior < 4.3 %']
PASS B13 slow CAS: a tap still opens the Exact page, which asks the CAS and says the tree waits for a tap
PASS B14 stale-key mode: no page skipped on the way to and through the Exact pages   []
PASS B15 help: four pages, page 4 "exact answers (CAS)", all text above y 218 and inside x 318
PASS B17 answers wrapped in quotes: the kit strips them, the panel still shows PPV = 2/3, NPV = 171/173   ['PPV = 2/3', 'NPV = 171/173', 'exact (CAS), tap', 'Most T+ are false', 'if prior < 5.3 %']
PASS B17 a decimal answer (approximate mode) is not shown as exact: PPV = 0.667, badge decimal   ['PPV = 0.667', 'NPV = 171/173', 'decimal, tap', 'Most T+ are false', 'if prior < 5.3 %']

== B16. beta 7's verify_BayesTree.py run against beta 8c (harness v3d) ==
   47 PASS, 5 FAIL
   FAIL A summary returned   BayesTree: PPV = 0.667 = 2/3, NPV = 0.988 (prior 0.100, sens 0.900, spec 0.950)
   FAIL B slider: one redraw per changed drag sample   ['prior 0.097', 'prior 0.010', 'prior 0.014', 'prior 0.860', 'prior 0.500', 'prior 0.500']
   FAIL B slider: all six boxes re-count at every sample   priors [0.097, 0.01, 0.014, 0.86, 0.5]
   FAIL E More cycles three pages and back   ['Values', 'Counts', 'ROC', 'PPV', '2×2', 'More']
   FAIL I breadcrumb 0.10 -> 0.67 -> 0.97   ('0.10', None, None)
PASS B16 every other beta 7 check passes on beta 8c (47 pass; the 5 intended changes listed above)   []

== G. beta 8 in harness v3d (the CAS finding stays), and beta 8b against beta 8a ==
PASS G beta 8 in v3d: its bt_Cas hands back its own text, so the panel shows decimals only (['PPV = 0.667', 'NPV = 0.988', 'decimal, tap'])   ['PPV = 0.667', 'NPV = 0.988', 'decimal, tap', 'Most T+ are false', 'if prior < 5.3 %']

G. beta 8b against beta 8a
PASS beta 8b: routines that differ from beta 8a: ['BayesTree', 'bt_FaganView', 'bt_PrevView', 'bt_RCnt', 'bt_RPrb', 'bt_RocView', 'bt_WaitAny', 'bt_fmtq'] (want ['BayesTree', 'bt_FaganView', 'bt_PrevView', 'bt_RCnt', 'bt_RPrb', 'bt_RocView', 'bt_WaitAny', 'bt_fmtq'])
PASS beta 8b: bt_RCnt, bt_RPrb, bt_fmtq are new
PASS beta 8b: one new file-level LOCAL line, the stale-click list
PASS beta 8b: outside those routines and that line only comments differ
PASS beta 8b: bt_Cas (the CAS call form) is byte-identical to beta 8a
  routines that differ from beta 8a: BayesTree, bt_FaganView, bt_PrevView, bt_RCnt, bt_RPrb, bt_RocView, bt_WaitAny, bt_fmtq; everything else differs only in comments

== S. 8b: soft keys under WAIT(-1), as the emulator answers (harness v3d) ==
PASS S1 8b: soft key 1 (Values) runs from the type-3 strip click alone   ['Exact Values'] ['BayesTree']
PASS S1 8b: soft key 2 (Counts) runs from the type-3 strip click alone   ['Leaf Counts (2x2)'] ['BayesTree']
PASS S1 8b: soft key 3 (ROC) runs from the type-3 strip click alone   [] ['BayesTree', 'bt_RocView']
PASS S1 8b: soft key 4 (PPV) runs from the type-3 strip click alone   [] ['BayesTree', 'bt_PrevView']
PASS S1 8b: soft key 5 (2×2) runs from the type-3 strip click alone   [] ['BayesTree', 'bt_Tbl2View']
PASS S2 8b: beta 8a in v3d: soft key 1 does nothing (the emulator: "tapping Values or ROC does nothing")   ['BayesTree']
PASS S2 8b: beta 8a in v3d: soft key 2 does nothing (the emulator: "tapping Values or ROC does nothing")   ['BayesTree']
PASS S2 8b: beta 8a in v3d: soft key 3 does nothing (the emulator: "tapping Values or ROC does nothing")   ['BayesTree']
PASS S3 8b: More (slot 6) steps page 1 -> 2 -> 3 -> 1 from type-3 clicks   ['Values', 'Diag', 'Test 2', 'Values']
PASS S3 8b: page 2 slot 5 (Help) opens the help pages   ['BayesTree', 'bt_HelpView']
PASS S3 8b: page 3 slot 4 (Leaves) turns the leaves into shares (T+ 0.090 ...)   ['T+ 0.090', 'T− 0.010', 'T+ 0.045', 'T− 0.855']
PASS S4 8b: a type-0 PRESS on the strip (v3b model: {0, x, y}, {2}) does nothing -- neutralised   []
PASS S4 8b: a firmware that sent {0}, {2} AND {3} for a strip tap would still run the key ONCE   ['Leaf Counts (2x2)']
PASS S4 8b: a tap on the root box ({0}, {2}, {3}) opens its node page once, not twice   1 node pages
PASS S4 8b: a tap on a branch number opens its page once, on the lift ({2}), not again on the click   1 node pages
PASS S5 8b: bt_PrevView closed by a tap on its footer (x 150, y 226): its {2}, {3} reach the tree and run no soft key   ['BayesTree', 'bt_PrevView'] []
PASS S5 8b: bt_RocView closed by a tap on its footer (x 100, y 226): its {2}, {3} reach the tree and run no soft key   ['BayesTree', 'bt_RocView'] []
PASS S5 8b: bt_FaganView closed by a tap on its footer (x 230, y 226): its {2}, {3} reach the tree and run no soft key   ['BayesTree', 'bt_FaganView'] []
PASS S5 8b: without the guard the PPV view's closing click WOULD run soft key 3 (ROC) on the tree   ['BayesTree', 'bt_PrevView', 'bt_RocView']
PASS S5 8b: the guard skips that one click only: a tap at the same spot afterwards runs ROC   ['BayesTree', 'bt_PrevView', 'bt_RocView']
PASS S6 8b: mouse_tail (not measured): a node page closed by a footer tap leaves its click, which the tree skips   ['BayesTree', 'bt_NodeInfo']
PASS S6 8b: mouse_tail: four help pages closed by footer taps, back on the tree, no soft key fired   ['BayesTree', 'bt_HelpView']
PASS S7 8b: the stale-click list is filled by the three WAIT(-1) views and bt_WaitAny, and reset by keys and presses
PASS S7 8b: no WAIT(-1) type-0 test at y >= 218 acts any more; the strip is read from type 3 only

== L. 8b: every pair on the tree adds up ==
PASS L1 8b: sens 0.835, D+ 100: T+ 84, T− 16 (84 + 16 = 100); D− 900: T+ 45, T− 855   ['T+ 84', 'T− 16', 'T+ 45', 'T− 855']
PASS L1 8b: beta 8a shows the emulator's T+ 84, T− 17 (101) for the same tree   ['T+ 84', 'T− 17', 'T+ 45', 'T− 855']
PASS L2 8b: 144 trees (priors, sens/spec pairs, N 10, 37, 1000): root = D+ + D−, D+ = TP + FN, D− = FP + TN, and every branch pair adds to 1   []
PASS L2 8b: every count is within one person of its exact value   []
PASS L2 8b: 12 two-test trees (root = test 1's positives): every pair adds up   []
PASS L3 8b: 6 trees in shares: every pair adds up at three decimals   []
PASS L3 8b: a share that rounds to 0 still says "< 0.001", not "0.000" (prior 0.0001: TP, FN, D+, the prior branch)   ['prior < 0.001', '< 0.001', 'D+ < 0.001', 'T+ < 0.001', 'T− < 0.001', 'odds < 0.001 × LR+ = 0.002']
PASS L4 8b: the FN box's page says "count = 16  (0.016 of N)", as the box   ['False negatives', 'count = 16  (0.016 of N)']
PASS L4 8b: the 2×2 view: 84 + 16 = 100, 45 + 855 = 900, columns 129 + 871 = 1000 (8a: 84 + 17 ≠ 100)   [(84.0, 16.0, 100.0), (45.0, 855.0, 900.0), (129.0, 871.0, 1000.0)]

== C. 8b: the first-level numbers off the branch lines ==
PASS C1 8b: the prior number (0.100 at x 98, y 78) does not touch either branch line   (97.0, 78.0, 126.5, 88.0)
PASS C1 8b: the 1 - prior number (0.900 at x 98, y 136) does not touch either branch line   (97.0, 136.0, 126.5, 146.0)
PASS C1 8b: nothing is drawn at the old spots (x 84, y 70 / 142)
PASS C1 8b: (for the record) the old spot x 84, y 70 lay on the upper branch line
PASS C2 8b: a tap on the moved number (110, 82) opens "Branch: P(D+) = prior"   ['Branch: P(D+) = prior']
PASS C2 8b: a tap on the moved number (110, 140) opens "Branch: P(D−) = 1 − prior"   ['Branch: P(D−) = 1 − prior']
PASS C3 8b: no tree text runs past x 318   []

== G (8c). beta 8c against beta 8b ==
PASS G 8c: routines that differ from beta 8b: ['BayesTree', 'bt_Cas', 'bt_Crumb', 'bt_DiagView', 'bt_ExactView', 'bt_FaganView', 'bt_HelpView', 'bt_NumS', 'bt_Pct', 'bt_PrevView', 'bt_Rep', 'bt_RocView', 'bt_Strip', 'bt_fmtq']   want ['BayesTree', 'bt_Cas', 'bt_Crumb', 'bt_DiagView', 'bt_ExactView', 'bt_FaganView', 'bt_HelpView', 'bt_NumS', 'bt_Pct', 'bt_PrevView', 'bt_Rep', 'bt_RocView', 'bt_Strip', 'bt_fmtq']
PASS G 8c: bt_Crumb is the one new routine; bt_WaitAny (it still appends its tap) is byte-identical
PASS G 8c: outside those routines the one new line is the threshold, "LOCAL btQueuedMs := 100;"; everything else is comments
PASS G 8c: bt_Cas keeps its IFERR call line and its quote strip byte-identical (only the INSTRING guard is new)
PASS G 8c: the stale test reads the threshold by name, and the threshold is set in ONE place
PASS G 8c: the type-3 soft-key logic the emulator confirmed is unchanged (slot MIN(6, IP(x/53.4)+1) on a non-stale type 3 at y >= 218)

== R. 8c: the second emulator round ==
PASS R1 8c: beta 8b, the emulator's case: 2x2 closed on its footer at the ROC key, then ROC once -> NOTHING (the tap is eaten by the stale list)   ['BayesTree', 'bt_Tbl2View']
PASS R1 8c: beta 8b: ... a second ROC tap works (the emulator: "the first tap is ignored, the second works")   ['BayesTree', 'bt_RocView', 'bt_Tbl2View']
PASS R1 8c: beta 8c: the same taps -- ROC opens on the FIRST tap (a real, later tap at the spot counts)   ['BayesTree', 'bt_RocView', 'bt_Tbl2View']
PASS R1 8c: the same at the Values key's spot: the 2x2 view closes there, the next tap there runs Values   ['BayesTree', 'bt_Tbl2View'] ['Exact Values']
PASS R1 8c: the same at the PPV key's spot: the 2x2 view closes there, the next tap there runs PPV   ['BayesTree', 'bt_PrevView', 'bt_Tbl2View'] []
PASS R1 8c: the same at the More key's spot: the 2x2 view closes there, the next tap there runs More   ['BayesTree', 'bt_Tbl2View'] []
PASS R1 8c: a click ALREADY QUEUED at the ROC spot (mouse_tail, a clock that has not moved (plain v3d)) is still skipped: no ROC   ['BayesTree', 'bt_Tbl2View']
PASS R1 8c: a click ALREADY QUEUED at the ROC spot (mouse_tail, the student's taps 400 ms apart) is still skipped: no ROC   ['BayesTree', 'bt_Tbl2View']
PASS R1 8c: ... and the real ROC tap after that queued click still counts: ROC opens once   ['BayesTree', 'bt_RocView', 'bt_Tbl2View']
PASS R1 8c: (with the stale test patched out, that queued click WOULD run ROC -- so the skip is real)   ['BayesTree', 'bt_RocView', 'bt_Tbl2View']
PASS R1 8c: PPV closed by a tap outside its plot (150, 205): its queued {2}, {3} run nothing on the tree   ['BayesTree', 'bt_PrevView']
PASS R1 8c: with time passing, a tap on the root box still opens its page once   1
PASS R1 8c: mouse_tail with time passing: a node page closed on its footer leaves its click, which is skipped   ['BayesTree', 'bt_NodeInfo']
PASS R2 8c: bt_PrevView closes on a footer tap that arrives only as {3, 150, 226}; back on the tree, nothing else opens   ['BayesTree', 'bt_PrevView'] left over 1
PASS R2 8c: (beta 8b in the same model: the footer tap does nothing, Esc has to close bt_PrevView -- round 2's finding)   left over 0
PASS R2 8c: bt_RocView closes on a footer tap that arrives only as {3, 100, 226}; back on the tree, nothing else opens   ['BayesTree', 'bt_RocView'] left over 1
PASS R2 8c: (beta 8b in the same model: the footer tap does nothing, Esc has to close bt_RocView -- round 2's finding)   left over 0
PASS R2 8c: bt_FaganView closes on a footer tap that arrives only as {3, 230, 226}; back on the tree, nothing else opens   ['BayesTree', 'bt_FaganView'] left over 1
PASS R2 8c: (beta 8b in the same model: the footer tap does nothing, Esc has to close bt_FaganView -- round 2's finding)   left over 0
PASS R2 8c: ROC closed by a footer tap at the PPV key's spot, then PPV tapped: PPV opens (no stale entry)   ['BayesTree', 'bt_RocView', 'BayesTree', 'bt_PrevView', 'BayesTree']
PASS R2 8c: bt_PrevView: a type-0 tap outside the plot still means back (kept as it was)   ['BayesTree', 'bt_PrevView']
PASS R2 8c: bt_RocView: a type-0 tap outside the plot still means back (kept as it was)   ['BayesTree', 'bt_RocView']
PASS R2 8c: bt_FaganView: a type-0 tap outside the plot still means back (kept as it was)   ['BayesTree', 'bt_FaganView']
PASS R2 8c: a drag inside the PPV plot still moves the prior (several frames) and does not close the view   4 frames
PASS R3 8c: the emulator's tree (prior 0.041, 0.835 / 0.95 twice), 6.5 px per character: .04 → .42 → .92, no overlap, ends at x 85.5 <= 102   [('.04', 2.0), ('→', 24.5), ('.42', 34.0), ('→', 56.5), ('.92', 66.0)]
PASS R3 8c: the same tree in v3d's own 5.5 px model keeps the leading zeros: 0.04 → 0.42 → 0.92 (ends at x 91.0)   [('0.04', 2.0), ('→', 27.0), ('0.42', 35.5), ('→', 60.5), ('0.92', 69.0)]
PASS R3 8c: the same tree with an 11-px arrow (stress): .04 → .42 → .92, no overlap, ends at x 94.5   [('.04', 2.0), ('→', 24.5), ('.42', 38.5), ('→', 61.0), ('.92', 75.0)]
PASS R3 8c: (beta 8b, fixed at x 2 / 31 / 38 / 67 / 74: with an 11-px arrow each arrow runs into the next number, the emulator's "0.04 -0.42 -0.92")   [('→', '0.42'), ('→', '0.92')]
PASS R3 8c: 72 two-test trees (12 priors x 6 test pairs, the extremes included), 6.5 px per character: every crumb is 5 pieces, none overlaps the one before, all end left of x 102   []
     forms used (6.5 px model; 0 = bt_fmtB as is, 1 = no leading zero, 2 = two decimals): {2: 27, 1: 45}
     with an 11-px arrow (stress): 42 of 72 still fit; those that do not: [((0.0001, (0.835, 0.95), (0.835, 0.95)), '<.01 → <.01 → .03', 103.5), ((0.0001, (0.9, 0.95), (0.9, 0.95)), '<.01 → <.01 → .03', 103.5), ((0.0001, (0.999, 0.999), (0.999, 0.999)), '<.01 → .09 → >.99', 103.5), ((0.0001, (0.5, 0.5), (0.6, 0.7)), '<.01 → <.01 → <.01', 110.0)]
PASS R3 8c: with an 11-px arrow nothing ever overlaps either (the layout follows the measured widths)
PASS R3 8c: if TEXTOUT_P handed back no position past its start, the crumb is laid out at 7 px a character (10 for the arrow): .04 → .42 → .92, ends at x 97.0   [('.04', 2.0), ('→', 26.0), ('.42', 39.0), ('→', 63.0), ('.92', 76.0)]
PASS R4 8c: two tests, Exact page 1: "then test 2: TP = 28586225, FP = 2397500," and "  FN = 5648775, TN = 45552500" on two lines   ['Exact answers', 'exact (CAS)', 'Picture N = 1000000000: 82185000 test + on test 1,', 'then test 2: TP = 28586225, FP = 2397500,']
PASS R4 8c: two tests: every Exact-page line inside x 318, at most 15 lines, the last at y <= 206 (above the footer at 226)   13 lines, last y 180.0, wide []
PASS R4 8c: two tests, forensic: every Exact-page line inside x 318, at most 15 lines, the last at y <= 206 (above the footer at 226)   15 lines, last y 206.0, wide []
PASS R4 8c: (beta 8b: that line was 69 characters, to x 388 -- off the 320-px screen)
PASS R5 8c: Diagnostics says "For p-values / CIs on real data: EpiStats 2×2." (inside x 318), and ConTable2 is named nowhere in the program's text   ['All are cell-proportion functions: valid for', 'expected (forward) AND observed (counts) tables.', 'For p-values / CIs on real data: EpiStats 2×2.', 'any key or tap = back']
PASS R6 8c: soft-key page 3 reads ['Test 2', 'Reset', 'Forens', 'Leaves', 'Exact', 'More']; every label of the three pages has at most 6 characters   ['Test 2', 'Values', 'Counts']
PASS R7 8c: bt_Rep: a pattern at the end, at the start, the whole text, an empty pattern, an empty text, twice, none -- all right, no error   []
PASS R7 8c: (beta 8b's bt_Rep STOPS on a pattern at the end and on an empty text: ['INSTRING: Invalid input (the first argum', 'INSTRING: Invalid input (the first argum'])
PASS R7 8c: bt_Strip("") = "", "{1/20}" -> 1/20, "list[1/20]" -> 1/20, "[ ]" -> "" (no error)   ['', '1/20', '1/20', '']
PASS R7 8c: bt_Cas with the CAS failing returns "" without an error
PASS R7 8c: bt_Cas still answers (1/3 -> "1/3") and refuses an infinity (1/0 -> "")   [('string(1/3)', '"1/3"', 65.62042236328125), ('string(1/0)', '"±∞"', 64.24760818481445)]
PASS R7 8c: cas=fail end to end (one test): the tree badge "decimal, tap", both Exact pages "decimal", no error   ['PPV = 0.161', 'NPV = 0.999', 'decimal, tap'] 2
PASS R7 8c: (beta 8b on the same run STOPS: INSTRING: Invalid input (the first argument is an empty stri)
PASS R7 8c: cas=fail end to end (two tests): the tree badge "decimal, tap", both Exact pages "decimal", no error   ['PPV = 0.973', 'NPV = 0.826', 'decimal, tap'] 2
PASS R7 8c: (beta 8b on the same run STOPS: INSTRING: Invalid input (the first argument is an empty stri)
PASS R7 8c: cas=fail end to end (forensic): the tree badge "decimal, tap", both Exact pages "decimal", no error   ['PPV = 0.667', '1−PPV = 0.333', 'decimal, tap'] 2
PASS R7 8c: (beta 8b on the same run STOPS: INSTRING: Invalid input (the first argument is an empty stri)
PASS R7 8c: cas=fail end to end (forensic, two tests, soft key Exact): the tree badge "decimal, tap", both Exact pages "decimal", no error   ['PPV = 0.971', '1−PPV = 0.029', 'decimal, tap'] 2
PASS R7 8c: (beta 8b on the same run STOPS: INSTRING: Invalid input (the first argument is an empty stri)
PASS R8 8c: bt_NumS(0.1,) = "0.1" (beta 8b: "0.1")   []
PASS R8 8c: bt_NumS(0.01,) = "0.01" (beta 8b: "0.01")   []
PASS R8 8c: bt_Pct(1.002002e-06,) = "0.000 %" (beta 8b: "1.002ᴇ-4 %")   []
PASS R8 8c: bt_Pct(0.00308,) = "0.31 %" (beta 8b: "0.31 %")   []
PASS R8 8c: bt_fmtq(0.001, 0.001) = "0.001" (beta 8b: "0.001")   []
PASS R8 8c: bt_fmtq(0.001, 0.001) = "0.001" (beta 8b: "0.001")   []
PASS R8 8c: bt_fmtq(0.0, 0.0002) = "< 0.001" (beta 8b: "< 0.001")   []
     harness runs of beta 8c in this script: 387; scientific STRING results: none
PASS R8 8c: no STRING(x, 2, d) of beta 8c printed in scientific form in any of the 387 runs   []
     (beta 8b in the same script: [(0.0001002002, 3, '1.002ᴇ-4')])

185 PASS, 0 FAIL
