# Where does the DIFFICULTY screen live? ✅ DECODED 2026-08-31.
# It is a DIALOG -- `DLG_SELECT_DIFFICULTY`, GP_DIALOG.pak entries 2/3.
#
# CLOSES A NEGATIVE OF MINE. gp-title-holds-three-button-screens.txt recorded
# "not an 8-record btn-named build anywhere on the disc", with the failed
# assumption named as mine: I assumed DIFFICULTY's four items pair with `f` focus
# variants in an archive of its own, the way GP_TITLE's screens do. Both halves
# of that were wrong -- it has its own button prefix and it is not a GamePart
# screen at all.
#
################################################################################
# ROUTE 1 -- THE IMAGE. /image/sylpheed.pe, 3 occurrences of "DIFFICULTY":
#   0x820A2548  STAGE | DIFFICULTY | TITLE | FADE | BASE_EXTRA ...
#               (a GamePartTask::RegisterToFactory name list)
#   0x820A3377  RECORD_DIFFICULTY   (a results/record field)
#   0x820A41BB  DLG_LEADERBOARD_MENU_NEXT | DLG_SYSTEM_PAUSE |
#               **DLG_SELECT_DIFFICULTY** | DLG_MISSION_OBJECTIVE |
#               DLG_MESSAGE_BOX | DLG_MESSAGE_BOX_YES_NO | ...
#
# ✅ The third is the answer: DIFFICULTY is one of the game's DLG_* dialogs.
# ⚠️ "GP_DIFFICULTY" appears 0 times in the image, which is consistent.
#
################################################################################
# ROUTE 2 -- THE DISC. GP_DIALOG.pak entries 2 and 3 are the only builds in that
# archive carrying `pcbtn00`..`pcbtn03` -- FOUR buttons, matching
# EASY / NORMAL / HARD / BACK. Design rows and spacing:
#
#   entry 2   y 259 / 329 / 399 / 469     spacing 70, 70, 70
#   entry 3   identical                    (⚠️ called "the EN/JP pair" here and
#                                          WITHDRAWN 2026-08-31 -- see the section
#                                          at the end; adjacent GP_DIALOG entries
#                                          are generally unrelated dialogs)
#
# ✅ CONTROL: the same reader on GP_TITLE entry 5 returns 162/242/322/401/482,
# spacing 80 -- the rows that archive is independently known to place.
#
################################################################################
# ROUTE 3 -- THE ORACLE. My own capture of the running DIFFICULTY screen
# (captures/menu-nav/live-difficulty-opens-normal.png), with the disc-grounded
# calibration capture_y = 64.82 + 0.9919 * design_y:
#
#   design row   predicted    measured in the capture   residual
#      259         321.7            323.5                +1.8
#      329         391.2            394.0                +2.8
#      399         460.6            463.5                +2.9
#      469         530.0            533.5                +3.5
#   measured spacing 70.5 / 69.5 / 70.0  against the disc's 70 / 70 / 70
#
# Four rows, all under 4 px, with the spacing agreeing exactly. The residual is a
# uniform ~+2.8 px offset, which is the calibration's own systematic and not a
# mismatch.
#
# => THREE INDEPENDENT ROUTES: the executable names it a dialog, the disc has a
#    four-button dialog build, and the running game draws its rows where that
#    build says they are.
#
# 📌 WHY IT MATTERS BEYOND THE LOCATION: DIFFICULTY being a DIALOG explains why
# NEW GAME's destination is not a screen in GP_TITLE, and it means the "four menu
# items load an external archive" reading of the event numbers
# (boot-config-and-gamepart-registry.md's count-match) is looser than it looked --
# NEW GAME opens a dialog from GP_DIALOG.pak, which is an external archive, but a
# dialog is not the same kind of thing as OPTIONS or TUTORIAL opening a GamePart.
# The count still matches; the categories are not uniform.
#
# ⚠️ REACH: entries 2/3 are identified by button count and geometry, not by a
# name binding DLG_SELECT_DIFFICULTY to a pak entry. No such binding was found --
# the DLG_* names live in a string list, and what maps a name to an archive entry
# is not decoded. Another 4-button dialog with the same rows would be
# indistinguishable by this evidence.

################################################################################
# ✅ DECODED 2026-08-31 (later): THE DIALOG TABLE. `DLG_SELECT_DIFFICULTY` = id 2000.
#
# Chasing the reach above -- "no binding from the DLG_ name to anything" -- found
# one. Every DLG_ string in the image is pointed at by exactly one aligned word,
# at a regular 12-byte stride. The table is:
#
#     struct { u32 id; u32 name_ptr; u32 handler; }   // 12 bytes, big-endian
#
# 🔴 CORRECTED 2026-08-31: this first read as `{handler, id, name_ptr}`, which is
# the same three fields SHIFTED BY ONE WORD, so every record was credited with the
# PREVIOUS record's handler. Caught by a control dump: under the old alignment
# record 0 (DLG_LET_SIGNIN) had a "handler" of 0x10000000, which is not a code
# address. ids and names are unaffected -- they are the same fields either way,
# and DLG_SELECT_DIFFICULTY is still id 2000. Only the handler attribution moved.
# Under the corrected alignment its handler is 0x821D0808, and the histogram over
# all 70 records is 0x821D0808 x43, 0x821D05D8 x24, 0x821CFD80 x3.
#
# spanning 0x820A0A2C .. 0x820A0D68, three distinct handler values
# (0x821CFD80, 0x821D05D8, 0x821D0808).
#
# ✅ COMPLETE: 70 DLG_ names in the image, 70 records, ZERO names without one.
# ids are banded and monotonic, with a single gap at 24:
#     0..23   sign-in, storage, save/load/replay, GO_TITLE, GO_NEXT
#     25..43  autosave, training, weapon develop, custom keys, menu jumps
#     98, 99  DLG_MESSAGE_BOX_YES_NO, DLG_MESSAGE_BOX
#     1000    DLG_MISSION_OBJECTIVE
#     2000    **DLG_SELECT_DIFFICULTY**
#     2001..3 SYSTEM_PAUSE, LEADERBOARD_MENU_JUMP, LEADERBOARD_MENU_NEXT
#     2100..15 DLG_STAGE_TITLE01..16
#     8000    DLG_RATING_ESRB
#     9000..2 trial dialogs
#
# Read from /image/sylpheed.pe directly -- these are the bytes the console ran,
# not a database row.
#
################################################################################
# ✅ REFUTATION ATTEMPT ON THE SHARED REACH -- IT SURVIVES, AND IS NOW BOUNDED.
#
# Both agents recorded: "another four-button dialog with the same rows would be
# indistinguishable by this evidence". Tested by scanning EVERY build in EVERY pak
# for four buttons within 6 px of rows 259/329/399/469
# (examples/four_button_row_rivals.rs):
#
#   INCUMBENT  GP_DIALOG.pak entry 2   rows [259, 329, 399, 469]
#   INCUMBENT  GP_DIALOG.pak entry 3   rows [259, 329, 399, 469]
#   control: 2 incumbents found (want 2) -- PASSED
#   RIVALS ELSEWHERE ON THE DISC: **0**
#
# So the hypothetical rival does not exist here. The geometric identification is
# UNIQUE DISC-WIDE, which is a stronger statement than the one either of us
# recorded, and it was cheap to get.
#
# ⚠️ WHAT IS STILL NOT BOUND: id 2000 -> a pak entry. The table gives name -> id
# and the disc gives a unique four-button build; nothing found so far connects the
# two. The tie is uniqueness of geometry plus the oracle capture, not a pointer.

################################################################################
# ❌ REFUTED: the id -> pak-entry join is NOT positional. 2026-08-31.
#
# GP_DIALOG.pak has exactly **140 entries** and the dialog table has exactly **70
# records** — a 2:1 ratio that looks like one EN/JP pair per dialog, which would
# make the unbound join an ordering question rather than a search. Tested, and it
# does not hold:
#
#   ADJACENT pairing (2k, 2k+1)   identical element-name sets:  2 of 65
#   HALVES   pairing (i, i+70)    identical element-name sets:  0 of 65
#   (5 pairs unreadable — entries that do not parse as builds)
#
# GP_TITLE's language pairs share their element sets exactly (except 4/7, the
# title art), so identical sets are the signature of a pair there. In GP_DIALOG
# almost nothing matches, so **the 2:1 ratio is not established as a language
# pairing** and no positional rule connects id 2000 to entries 2/3.
#
# 📌 RESIDUAL OBSERVATION, recorded because it is odd rather than because it is
# understood: the only two adjacent pairs with identical element sets are
# **entries 0/1 and 2/3** — and 2/3 is the DIFFICULTY build. Whatever makes those
# two structurally uniform in an archive where 63 of 65 pairs are not, this does
# not explain.
#
# ⚠️ A plausible reading I am NOT asserting: dialog text may be baked into
# language-specific sprites, which would make EN/JP entries differ in element
# names by construction. That is consistent with the 63, and it is one
# measurement away from being tested — but it is not tested here, and the 2 that
# DO match would then need their own explanation.
#
# => The join stays unbound. Table gives name -> id; disc gives a unique build;
#    the tie is uniqueness plus the oracle capture. Positional ordering is now
#    ruled out as the missing pointer, which narrows where to look next.

################################################################################
# 🔴 MY UNTESTED READING IS REFUTED, and it inverts the puzzle rather than
# solving it. 2026-08-31, sylpheed-port, re-derived here with my own reader.
#
# I offered: dialog text may be baked into language-specific sprites, so EN/JP
# entries differ in element names by construction -- which would explain the 63
# differing pairs and leave the 2 matching ones needing their own account.
#
# ❌ **26 of 65 adjacent pairs differ in BUTTON COUNT.** Two languages of one
# dialog cannot: a locale changes the glyphs on a button, not how many there are.
# Reproduced independently (examples/dialog_pair_button_counts.rs): 26 differing,
# 39 equal, 5 unreadable -- their count exactly.
#
#   entries  6/7   2 vs 3      entries 44/45  2 vs 0
#   entries  8/9   2 vs 0      entries 46/47  2 vs 0
#
# And the names say it once read rather than counted: 6/7 is ranking_NEXT against
# ranking_JUMP, 8/9 is py_ranking_* against pzeff*, 10/11 is pzstg10 against
# pzstg02 -- different subsystems, different stages.
#
# 📌 SO THE PUZZLE DISSOLVES INSTEAD OF DEEPENING. Adjacent GP_DIALOG entries are
# simply UNRELATED DIALOGS. The 63 never needed the language reading, so the 2
# that match need no special explanation either, and the 140:70 ratio is a
# **coincidence of counting, not a pairing** -- which is the same fact my own
# halves-pairing result of 0 was already showing from the other side.
#
# ⚠️ AND THE CAREFUL PART, which is theirs and which I am preserving: this does
# NOT establish that 0/1 and 2/3 ARE EN/JP pairs. Identical element sets is the
# signature in GP_TITLE; here it is equally consistent with a DUPLICATE. And 37
# of the 63 differ WITHOUT a button-count mismatch -- for those the language
# reading is UNSUPPORTED, not refuted. What is refuted is it as an explanation of
# the 63, which is what I offered it as.
#
# 🔴 CONSEQUENCE FOR A DELIVERED CLAIM: I described entries 2/3 as "an EN/JP pair"
# in HANDOFF.md and above. **Withdrawn.** The DIFFICULTY identification does not
# rest on the pairing -- it rests on the unique four-button geometry (0 rivals
# disc-wide) plus the oracle capture -- but the pairing was stated as fact and was
# not one.

################################################################################
# ❌ AND THE 37 ARE NOW REFUTED TOO, not merely unsupported. 2026-08-31.
#
# Both agents recorded that the language reading survived for the 37 pairs that
# differ WITHOUT a button-count mismatch, and both noted that nothing rewarded
# closing it. It cost one scan.
#
# STEP 1: all 39 equal-button-count pairs share their button NAMES AND ROWS
# exactly (examples/dialog_pair_37.rs; control: entries 2/3 counted as matching).
# ⚠️ That does NOT settle it -- two different dialogs sharing a button template,
# like two yes/no boxes, look identical by that test.
#
# STEP 2: look at what actually differs (examples/dialog_pair_diffs.rs):
#
#   entries 10/11   pzstg10_01..20 + _eff   vs   pzstg02_01..16 + _eff
#   entries 12/13   pzstg11_*               vs   pzstg03_*
#   entries 14/15   pzstg12_*               vs   pzstg13_*
#   entries 16/17   pzstg04_*               vs   pzstg14_*
#   entries 18/19   pzstg05_*               vs   pzstg15_*
#   entries 20/21   pzstg06_*               vs   pzstg16_*
#
# ✅ THESE ARE DIFFERENT STAGES. They are the sixteen DLG_STAGE_TITLE01..16
# dialogs from the table above, and an adjacent pair carries TWO DIFFERENT STAGES,
# not two languages of one. That settles it unaided.
#
# 🔴 A SECOND ARGUMENT I OFFERED HERE IS WITHDRAWN. I wrote: "the sprite COUNTS
# differ too (stg10 has 20 title sprites, stg02 has 16), which is a different
# amount of text, not a translation of the same text." **It does not hold
# uniformly.** sylpheed-port re-ran it and 12/13 comes out EQUAL; my own output
# above shows it -- pzstg11_01..13 against pzstg03_01..13, thirteen each. I
# generalised from the 10/11 example I had looked at.
# ⚠️ Their absolute figures also differ from mine (42 vs 34 where I said 20 vs 16)
# because we counted different things: they count every `.t32` element in the
# entry, I counted only the differing stage-title lines. Both are legitimate; I
# did not say which I meant.
# 📌 The conclusion is untouched -- the stage numbers carry it alone. What this
# is worth is the shape: a conclusion resting on two legs, one of which does not
# reproduce. **The leg carrying no weight is the one that went unchecked**, which
# is the `EN/JP pair` failure one step out, committed while writing up that very
# failure.
#
# => The language reading is refuted for the 37 as well. The whole 63 is now
#    explained by one fact: **adjacent GP_DIALOG entries are unrelated dialogs.**
#    No residue, no special case.
#
# 📌 THE 2 REMAINING PAIRS (0/1 and 2/3) are still the only ones with identical
# element sets, and still unexplained -- but they are no longer anomalous against
# a hypothesis, because the hypothesis is gone. Whether they are a language pair,
# a duplicate, or two dialogs sharing every element is untested.
#
# ⚠️ WORTH RECORDING ABOUT THE PROCESS, not the disc: this question was left open
# by both agents with the explicit observation that "nothing rewards closing it".
# It cost two scans and went AGAINST the reading I had offered. A bound nobody is
# incentivised to test is exactly where a convenient claim survives -- and the
# next reader cannot tell whether a bound was respected or merely never revisited.


################################################################################
# ❌ THE id -> PAK-ENTRY BINDING IS NOT IN THE IMAGE BY THIS ROUTE. 2026-08-31.
#
# Positional ordering was already ruled out. The next route was the dialog
# table's own handlers: if anything joins a dialog id to an archive entry, the
# code that builds a dialog should touch it.
#
# All three handlers were disassembled from the image. All three begin by loading
# the SAME global -- `lis r11,0x828E` then `lwz r3,0x2B14(r11)` -> 0x828E2B14 --
# and two take addresses at 0x828E45E0 / 0x828E4640 / 0x828E467C.
#
# ❌ EVERY ONE OF THOSE IS BSS. They sit inside a single contiguous ZERO RUN of
# 364 601 bytes (0x828A28C7 .. 0x828FB900) -- uninitialised data, zero in the
# image, populated only at runtime.
#
# ✅ CONTROL, because an all-zero read is also what a bad address gives: the
# dialog table itself at 0x820A0A2C reads non-zero through the same arithmetic
# (10000000 00000000 820a4598 821cfd80). The addressing is right; the data is
# genuinely absent.
#
# => The handlers operate on RUNTIME state. If the id -> entry join exists there,
#    it is visible only in a running game, not in the image. That is a route
#    closed rather than a question answered, and it says where the next attempt
#    has to look: guest memory at 0x828E2B14 with the game up.
#
# ⚠️ REACH: one route (the table's own handlers). Not looked at: the archive
# loader, the GamePart that opens GP_DIALOG, or any table keyed by id elsewhere
# in the image. "Not in the image" is NOT established -- what is established is
# "not reachable from the dialog handlers, because they read BSS".
