# FOUR screen changes, per frame, from the running game. 2026-08-30.
# tools/re-capture/fade_decompose.sh (WHERE=menu | title | extras)
#
# Captures 2 and 4 are the SAME transition, title -> menu via (A), run twice.
# They are the hold-vs-load test: a load varies with cache and contention,
# a deterministic hold does not. The pair carries its own control -- the
# press-to-first-change latency DIFFERS by ~12 frames between the two runs,
# so conditions demonstrably were not identical, while the black gap is
# exactly 3 frames in both.
#
#   quantity                    run 1 (cap 2)          run 2 (cap 4)
#   outgoing quad rise          67-70: 63,127,191,255  64-67: 63,127,191,255
#   frames black ([255] alone)  70,71,72 = 3           67,68,69 = 3
#   incoming appears            frame 73               frame 70
#   incoming decay              255,-,127,84,63        255,169,127,84,42
#   press -> first change       ~25 frames             ~10 frames

############ CAPTURE 1 -- menu -> title, via (B) ############
frame  untextured full-screen   textured (distinct)        draws tex
   28  [64]                   [142, 146, 192, 255]         12  10
   29  [64]                   [143, 146, 192, 255]         12  10
   30  [64]                   [143, 147, 192, 255]         12  10
   31  [64]                   [143, 147, 192, 255]         12  10
   32  [64]                   [144, 148, 192, 255]         12  10
   34  [64, 255, 64]          [144, 148, 169, 191, 254, 255]   15  12
   35  [64, 223, 64]          [84, 143, 145, 149, 191, 255]   15  12
   36  [64, 207, 64]          [42, 119, 145, 149, 159, 255]   15  12
   37  [64, 175, 64]          [71, 95, 145, 149, 191, 255]   14  11
   39  [64, 95, 64]           [146, 150, 255]              11   8
   40  [64, 31, 64, 102]      [146, 151, 255]              12   6
   41  [64, 15, 64, 127]      [146, 151, 255]              12   6
   43  [64, 64, 255]          [147, 152, 255]              12   6
   44  [64, 64, 255]          [147, 152, 255]              12   6
   45  [64, 64, 255]          [148, 152, 255]              12   6
   46  [64]                   [255]                         6   2
   47  [64]                   [32, 255]                     8   6
   49  [64]                   [32, 96, 255]                 8   6
   50  [64]                   [48, 128, 255]                8   6

############ CAPTURE 2 -- title -> menu, via (A), run 1 ############
frame  untextured full-screen   textured (distinct)        draws tex
   60  []                     [42, 50, 55, 84, 255]         9   8
   61  []                     [16, 18, 255]                 8   7
   62  []                     [235, 255]                    7   6
   63  []                     [196, 255]                    7   6
   64  []                     [156, 255]                    7   6
   65  []                     [117, 255]                    7   6
   66  []                     [78, 255]                     7   6
   67  [63]                   [19, 255]                     8   4
   68  [127]                  [255]                         6   2
   69  [191]                  [255]                         6   2
   70  [255]                  [255]                         6   2
   71  [255]                  [255]                         6   2
   72  [255]                  [255]                         6   2
   73  [64, 255]              [255]                         7   3
   75  [64, 127]              [2, 252, 255]                 7   3
   76  [64, 84]               [3, 251, 255]                 7   3
   77  [64, 63]               [3, 251, 255]                 7   3
   78  [64]                   [5, 249, 255]                 7   3
   79  [64]                   [5, 249, 255]                 7   3
   80  [64]                   [7, 32, 247, 255]             8   6
   81  [64]                   [8, 96, 246, 255]             8   6
   82  [64]                   [8, 160, 246, 255]            8   6

############ CAPTURE 3 -- EXTRAS -> menu, via (B) ############
frame  untextured full-screen   textured (distinct)        draws tex
   28  [64]                   [128, 171, 181, 255]         11   9
   29  [64]                   [128, 172, 182, 255]         11   9
   30  [64]                   [111, 127, 172, 182, 185, 255]   11   9
   31  [64]                   [42, 79, 139, 172, 183, 223, 255]   11   9
   32  [64]                   [31, 69, 127, 173, 183, 255]   10   8
   33  [64]                   [31, 173, 184, 255]           9   7
   34  [64, 51]               [174, 184, 255]               8   4
   35  [64, 102]              [174, 184, 255]               8   4
   36  [64, 178]              [174, 185, 255]               8   4
   37  [64, 229]              [174, 185, 255]               8   4
   38  [64, 255]              [175, 186, 255]               8   4
   39  []                     []                            3   0
   40  []                     []                            3   0
   41  [64, 169]              [1, 253, 255]                 7   3
   42  [64, 148]              [2, 252, 255]                 7   3
   43  [64, 106]              [2, 252, 255]                 7   3
   44  [64, 63]               [3, 251, 255]                 7   3
   45  [64, 21]               [4, 250, 255]                 7   3
   46  [64]                   [5, 249, 255]                 7   3
   47  [64]                   [6, 248, 255]                 7   3
   48  [64]                   [7, 32, 247, 255]             8   6
   49  [64]                   [8, 96, 246, 255]             8   6
   50  [64]                   [9, 192, 245, 255]            8   6

############ CAPTURE 4 -- title -> menu, via (A), run 2 ############
frame  untextured full-screen   textured (distinct)        draws tex
   61  []                     [137, 255]                    7   6
   62  []                     [98, 255]                     7   6
   63  []                     [78, 255]                     7   6
   64  [63]                   [19, 255]                     8   4
   65  [127]                  [255]                         6   2
   66  [191]                  [255]                         6   2
   67  [255]                  [255]                         6   2
   68  [255]                  [255]                         6   2
   69  [255]                  [255]                         6   2
   70  [64, 255]              [255]                         7   3
   71  [64, 169]              [1, 253, 255]                 7   3
   72  [64, 127]              [2, 252, 255]                 7   3
   73  [64, 84]               [3, 251, 255]                 7   3
   74  [64, 42]               [4, 250, 255]                 7   3
   75  [64]                   [5, 249, 255]                 7   3
   76  [64]                   [6, 248, 255]                 7   3
   77  [64]                   [7, 32, 247, 255]             8   6
   78  [64]                   [8, 96, 246, 255]             8   6
   79  [64]                   [9, 192, 245, 255]            8   6
   80  [64]                   [10, 244, 255]                8   6

################################################################################
# A THIRD title -> menu REPLICATE, 2026-08-30 -- from a run that executed the
# WRONG EXPERIMENT. The script was invoked as WHERE=menu2extras but a condition
# edit had silently failed to apply, so it took the `title` branch instead. The
# capture is well-formed and is of a different transition than intended -- the
# same shape as the build-ordinal error, caught only because the log lacked the
# navigation lines the intended branch prints.
#
#   run              outgoing ramp              black frames   incoming decay
#   1 (fadecap2)     67-70: 63,127,191,255      70,71,72 = 3   73-77
#   2 (fadecap4)     64-67: 63,127,191,255      67,68,69 = 3   70-74
#   3 (m2e)          92-95: 63,127,191,255      95,96,97 = 3   98-103
#
# ✅ THREE INDEPENDENT RUNS, gap = 3 frames every time, and the outgoing ramp is
# byte-identical in all three (63, 127, 191, 255 -- steps of exactly 64). That
# strengthens "the black gap is not a load" from two replicates to three, and the
# ramp's exactness across runs makes the 4-frame outgoing duration as solid as
# anything measured here.
#
# 🟡 STILL OPEN: menu -> EXTRAS, the reverse of the pair measured at a 2-frame
# gap. The instrument is fixed (WHERE=menu2extras now reaches its branch) and the
# run has not been taken.

################################################################################
# FIFTH TRANSITION: menu -> EXTRAS via (A). 2026-08-30.
# The reverse of the pair already measured at a 2-frame gap, taken to test whether
# the black gap is a property of the screen PAIR or of the DIRECTION.
#
# Navigation verified both ways before arming: extras margin 11.23, back on the
# menu margin 11.60, against the discriminator's 9.9-11.7 control band. And the
# run announced its effective configuration -- "branch taken = menu2extras: back
# on the MENU with focus restored -> press (A)" -- which is the guard added after
# the previous run silently took the wrong branch.
#
#   frames 42-46  outgoing quad 51, 102, 153, [45 absent], 255  -- 5 frames,
#                 matching build 5's declared close of 10 units = 5 frames
#   frame  49     EMPTY: 3 draws, 0 textured
#   frames 51+    EXTRAS building
#
# ⚠️ Frames 48 and 50 carry no `--- frame` header at all, so the gap is ONE logged
# empty frame with two unlogged neighbours. Quoted as 1, not silently rounded to 3.
#
################################################################################
# ALL FIVE, ORDERED BY OUTGOING SCREEN -- which is the first thing that orders them
#
#   transition              black gap   outgoing         outgoing close (disc)
#   menu -> title    (B)    0           menu (build 5)   10 units = 5 frames
#   menu -> EXTRAS   (A)    1           menu (build 5)   10 units = 5 frames
#   EXTRAS -> menu   (B)    2           EXTRAS (build 6) 10 units = 5 frames
#   title -> menu    (A) x3 3, 3, 3     title (build 4)    8 units = 4 frames
#
# 🟡 THE GAP TRACKS THE OUTGOING SCREEN, not the direction and not the button: the
# two transitions leaving the MENU give 0 and 1, the one leaving EXTRAS gives 2,
# and the three leaving the TITLE give 3 every time. Direction is ruled out --
# EXTRAS->menu (2) and menu->EXTRAS (1) are the same pair in both directions and
# differ; button is ruled out -- (B) gives 0 and 2, (A) gives 1 and 3.
#
# 🔴 BUT THAT IS NOT YET A RULE. With three outgoing screens and one value each
# (bar the title's three), "each outgoing screen has its own gap" only restates
# the data; a rule would PREDICT. And nothing declared does: the outgoing close is
# 5, 5, 5, 4 frames against gaps 0/1, 2, 3 -- if anything inverted, on three
# points. Recorded as a narrowing of WHERE to look, not as a rule.

################################################################################
# SIXTH TRANSITION: menu -> a screen OUTSIDE GP_TITLE, via (A). 2026-08-30.
#
# Taken because sylpheed-port's BLOCKED row asks for a SECOND VALUE ON ONE
# OUTGOING SCREEN -- the thing that would make "the gap tracks the outgoing
# screen" predictive rather than a restatement. ⚠️ The menu is the only screen in
# GP_TITLE that can supply it: the title's sole exit is (A) to the menu and
# EXTRAS's sole exit is (B) to the menu, so neither has a second destination.
#
# ⚠️ CONFOUND NAMED IN ADVANCE, before the result was seen: this transition leaves
# the ARCHIVE, so a pak load could inflate the gap for reasons having nothing to
# do with the outgoing screen.
#
#   frames  4-21   menu settled ([64] = pteff02.prm)
#   frames 24-28   outgoing quad 25, 127, 255 -- 4-5 frames, matching build 5's
#                  declared close of 10 units = 5 frames
#   frame  30      EMPTY: 3 draws, 0 textured
#   frames 32+     the new screen builds ([127] primitive, not the menu's [64])
#
# ✅ GAP = 1, the same as menu -> EXTRAS. So the confound is MEASURED ABSENT:
# leaving the archive costs no extra black. That is worth having on its own.
#
################################################################################
# SIX TRANSITIONS, GROUPED BY OUTGOING SCREEN
#
#   outgoing screen      gaps            n
#   menu   (build 5)     0, 1, 1         3   -> title, -> EXTRAS, -> another archive
#   EXTRAS (build 6)     2               1   -> menu
#   title  (build 4)     3, 3, 3         3   -> menu (three runs)
#
# 🟡 The ordering menu {0,1} < EXTRAS {2} < title {3} now rests on 3 + 1 + 3
# measurements rather than 2 + 1 + 3, and the menu's three values agree to within
# ONE frame across three different destinations, one of them in another pak.
#
# 🔴 Still not predictive. Nothing declared separates 0/1 from 2 from 3: the
# outgoing closes are 5, 5, 4 frames for menu, EXTRAS, title against gaps of
# {0,1}, {2}, {3}. And EXTRAS still has n=1 with no way to get a second value.

################################################################################
# SEVENTH TRANSITION: EXTRAS -> a screen outside GP_TITLE, via (A). 2026-08-30.
#
# 🔴 Taken because my own claim that EXTRAS had a SOLE EXIT was wrong. I recorded
# its n=1 as STRUCTURAL; the disc refutes that -- build 6 declares three buttons,
# ptbtn11/ptbtn12/ptbtn13, all kind 0x3002. The cap was an unverified assertion.
#
#   frames 28-35   EXTRAS settled ([64]); textured content fades 31-35
#   frames 36-40   outgoing quad 25, 178, 229, 255 -- 4-5 frames, matching
#                  build 6's declared close of 10 units = 5 frames
#   frames 42,43,44  EMPTY: 3 draws, 0 textured  -- THREE frames
#   frames 45+     a different archive builds (23-28 draws/frame against
#                  GP_TITLE's 11-14)
#
# ✅ GAP = 3. So EXTRAS as outgoing screen gives {2, 3}.
#
################################################################################
# SEVEN TRANSITIONS, BY OUTGOING SCREEN
#
#   outgoing            gaps        n   destinations
#   menu   (build 5)    0, 1, 1     3   title, EXTRAS, another archive
#   EXTRAS (build 6)    2, 3        2   menu, another archive
#   title  (build 4)    3, 3, 3     3   menu x3
#
# 📌 A PAIRWISE CONTROL that holds the destination class constant: menu -> another
# archive gives 1, EXTRAS -> another archive gives 3. Same kind of destination,
# gap differs by the outgoing screen. That is the strongest support yet for the
# outgoing-screen dependence, because it removes the destination as the variable.
#
# 🔴 BUT THE CLEAN ORDERING IS GONE. EXTRAS {2,3} and title {3,3,3} now OVERLAP at
# 3, so "menu < EXTRAS < title" no longer separates them. What survives is weaker:
# the outgoing screen constrains the gap to a 2-wide band, and different outgoing
# screens have different bands that are not disjoint. Still not predictive, and
# now not even cleanly ordered.

################################################################################
# EIGHTH TRANSITION: a SECOND EXTRAS -> menu, via (B). 2026-08-30.
# Taken to verify the fixed effective-config guard on the one screen screen_id.py
# cannot resolve, and to replicate the table's weakest cell at the same time.
#
# ✅ THE GUARD WORKS, verified in a run rather than asserted:
#     arming on       = menu  [screen_id: cannot separate menu/EXTRAS]
#     discriminator   = extras  rmse=18.94  (other main_menu 30.09, margin 11.15)
#   Before the fix this run would have announced "arming on = menu" while armed on
#   EXTRAS. The ambiguity is now visible instead of hidden.
#
#   frames 29-31   outgoing quad 229, 255, 255
#   frames 32, 33  EMPTY: 3 draws, 0 textured
#   frames 34-38   incoming menu's quad decaying 169, 148, 106, 63, 21
#   GAP = 2, identical to the first EXTRAS -> menu.
#
################################################################################
# 📌 EIGHT TRANSITIONS: THE GAP IS A PROPERTY OF THE ORDERED PAIR, NOT THE ORIGIN
#
#   transition        gaps       n   repeats agree?
#   title  -> menu    3, 3, 3    3   YES
#   EXTRAS -> menu    2, 2       2   YES
#   menu   -> title   0          1   -
#   menu   -> EXTRAS  1          1   -
#   menu   -> other   1          1   -
#   EXTRAS -> other   3          1   -
#
# EVERY repeated pair is identical -- 3/3 and 2/2, five replicates, no variation.
# EVERY differing value comes from a DIFFERENT pair. And the same origin gives
# different values to different destinations: menu 0 vs 1, EXTRAS 2 vs 3.
#
# 🔴 So "the outgoing screen determines the gap" is superseded a second time. The
# origin CONSTRAINS it (menu {0,1}, EXTRAS {2,3}, title {3}); the ORDERED PAIR
# determines it, reproducibly. Still nothing declared predicts which value a pair
# gets, so this remains a description with five replicates behind it rather than a
# rule.

################################################################################
# NINTH TRANSITION: menu -> a SECOND screen outside GP_TITLE, via (A). 2026-08-30.
#
# Taken because the ordered-pair claim needs a second distinct destination from
# the SAME origin -- data, not a fit. sylpheed-port checked "nothing declared
# predicts the gap" independently and confirmed it, and DECLINED to search
# combinations on the grounds that four pairs against many candidate two-screen
# functions fits by construction. This adds a pair instead.
#
# ⚠️ The button is not controlled -- there is no focus readout -- so the
# destination is IDENTIFIED AFTERWARDS by its draw signature:
#     menu -> other (1st):  incoming primitive [127],  12-13 draws/frame
#     menu -> other (2nd):  incoming primitive [255],   7-9  draws/frame
#   Different screens.
#
#   frames 21-34   menu settled ([64]); textured content fades 32-34
#   frames 37-42   outgoing quad 25, 51, 102, 229, 255
#   frame  44      the new screen is ALREADY drawing -- [255] plus textured
#                  content. NO empty frame anywhere.
#
# ✅ GAP = 0.
#
################################################################################
# NINE TRANSITIONS. The menu as origin now gives FOUR values across FOUR
# destinations: title 0, EXTRAS 1, other-1 1, other-2 0.
#
# 📌 That is further evidence for the ordered pair over the origin: the same
# origin gives both 0 and 1 depending on where it goes, and the two repeated pairs
# remain internally identical (3,3,3 and 2,2).
#
# 🟡 AN OBSERVATION, EXPLICITLY NOT A RULE. The incoming screen's own full-screen
# primitive differs between the two "other" destinations: [255] where the gap is 0,
# [127] where it is 1. A screen that begins from opaque black would not need a
# blank frame, since its own backdrop covers it -- which is a tempting mechanism
# and it FAILS on menu -> EXTRAS: EXTRAS declares a black backdrop
# (ui-forced-backdrop.md, 12 of 16) and still gives 1.
# 🔴 So it is recorded as an observation with its counter-example, not fitted. Nine
# transitions against many candidate two-screen functions is the same construction
# sylpheed-port declined to search, and their reason applies unchanged to me.

################################################################################
# CAN THE TWO "other" DESTINATIONS BE NAMED? Attempted 2026-08-30, FAILED.
#
# sylpheed-port's caveat on the ninth pair: the destination identification is
# after the fact by draw signature, which establishes THAT the two screens differ
# ([255] at 7-9 draws/frame against [127] at 12-13) but not WHICH screen either
# is. The gap value is attributed to a pair whose second member is known only as
# "not the other one". Correct, and worth trying to remove.
#
# Both runs saved a screenshot of the destination. Scored against the archives the
# menu's non-EXTRAS buttons plausibly lead to:
#
#   m2o   GP_OPTIONS 43.30  GP_MISSION_SELECT 49.18  GP_SYSTEM 54.64
#         GP_SAVE_LOAD 54.79  GP_TUTORIAL 55.56        -> best margin 5.88
#   m2o2  GP_SYSTEM 45.74  GP_MISSION_SELECT 48.02  GP_OPTIONS 49.44
#         GP_TUTORIAL 56.54  GP_SAVE_LOAD 57.00       -> best margin 2.28
#
# 🔴 REJECTED, against this corpus's own calibration. which_title_screen.py's
# control puts a TRUE match at RMSE ~18-20 with a margin of ~10, and a "neither"
# at ~34 with a margin under 1. These best fits are 43 and 46 -- roughly double a
# real match -- with margins of 5.88 and 2.28. Accepting "m2o is GP_OPTIONS" on
# 5.88 would be the same weak-margin acceptance a threshold was added to the
# navigation search to prevent, three iterations ago.
#
# ⚠️ Reach of the negative: one build per archive was rendered (the default, which
# is the largest), and the screen a button opens need not be the largest build.
# So this does not refute those archives -- it fails to identify, which is
# different. The port's caveat stands and the ninth pair keeps it.
