diff --git a/docs/port/BLOCKED.md b/docs/port/BLOCKED.md index d4e3d7b5..352bdc6b 100644 --- a/docs/port/BLOCKED.md +++ b/docs/port/BLOCKED.md @@ -486,3 +486,29 @@ so it should sit the safe side of the Ⓐ blocker. at all** where the oracle measures a plateau, and both boundary frames still carry picture (alpha 7 and 34), so the true hold is shorter than whatever this lands on. + +--- + +## Does the game's menu music duck under a cutscene? + +*Derived from HANDOFF `9ca1eb5`. Raised 2026-08-29 by the port.* + +The port plays the main-menu bed **underneath `S00A`**, so two unrelated music +tracks sound at once. `MenuAudio.stop_bed()` exists and has no caller — this is +an **unmade decision**, not a choice, and it has been true since P6. + +🔴 **Deliberately not fixed.** Stopping the bed would sound right and would be +invented; MISSION's rule is to leave the unmeasured detail plainly wrong. The +runtime now announces it on every movie that starts with the bed sounding. + +What would settle it: **any capture with sound of the real game entering a +cutscene from the main menu** — the first second answers it. Three outcomes are +all useful: the music stops, it ducks, or it genuinely continues (in which case +the port is already right and this row closes as ✅). + +⚠️ Do **not** answer this from our own renderer or by reasoning about what a +shipped game would do. That reasoning is what makes an invented answer feel safe. + +⚠️ Related but separate, and already authored with a `why`: the bed **loops by +restart**, seam and all (`authored/audio.json`, `loop_why`). That is a known-ugly +deliberate choice pending a loop point, not this question. diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index d4ae8eed..9c167bfd 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -5624,3 +5624,60 @@ weak evidence for **any** rule, since every rule preserving declaration order agrees with it. ✅ Their claim survives, but on evidence they did not cite: it is `main_menu`'s `pteff00` that rules out the trivial reading, not the save/load frame itself. + +## The menu bed plays under the cutscene, nobody decided that, and it stays + +`MenuAudio.stop_bed()` exists and is **called from nowhere**. So the music that +starts when the main menu goes live runs through the cutscene and on past it — +and since `authored/audio.json` sets `loop: "restart"`, it then loops. Both +follow from the source and the authored data alone; no measurement is needed to +establish them. + +The port therefore emits **two unrelated music tracks at once** during `S00A`: +the movie carries its own music and effects, and the menu bed is underneath it. + +### It is not being fixed, and that is the decision + +`PORT-MISSION`'s rule is to leave an unmeasured detail **plainly wrong rather +than plausibly invented**, and this is the textbook case for it. Music over a +cutscene is wrong in a way any listener catches in one second. Ducking or +stopping the bed would sound entirely right — and would be a guess about a game +nobody has watched. **The audible version gets fixed; the plausible version ships +forever.** + +So `_play_video` now *announces* it, the way `skipped_chain` already announces +the two screens NEW GAME jumps over: + +``` + -> video S00A at 1.13 s (…) + 🔴 the menu bed is STILL PLAYING under this movie -- unmeasured, + left audible on purpose (BLOCKED.md: does menu music duck?) +``` + +It fires on the menu path and correctly stays silent on the boot path, where no +bed has started. `stop_bed` is **kept**, not deleted: the day a capture says +whether the game's menu music ducks under a movie, it is the one line to change. + +⚠️ This is the mirror of `ScreenView.skipped` from the previous iteration — a +fact recorded and never surfaced, against a capability provided and never used. +Both were invisible for the same reason: **nothing fails when they are missed.** + +### 🔴 And my correlator is not trustworthy on music under music + +Chasing this I ran the envelope correlator over the P7 recording repeatedly and +got answers that moved with the window and the template: the bed at r=0.42 with +one template and no peak at all above 0.4 with another; a post-movie window +search whose range **excluded the correct answer** and duly reported the bed's +own loop as unidentifiable. I was drafting *"46 s of unexplained audio after the +movie"* when the explanation was the authored `loop: "restart"` sitting in a file +I had not re-read. + +The instrument is sound where it was validated — discrete SFX against a bed, with +margins of +0.5 over a negative control. It is **not** sound for music under +music at comparable level, where every candidate scores 0.15–0.42 and nothing +separates. ⚠️ A margin is only meaningful against a control **at the same SNR**, +and I did not have one here. That is the fourth near-miss of this kind, and the +first where I would have invented an *anomaly* rather than a defect. + +Nothing in this section rests on that correlator. The finding is `stop_bed` having +no caller, which is a fact about the source. diff --git a/port/scripts/boot.gd b/port/scripts/boot.gd index f9c32bf2..f3d204ea 100644 --- a/port/scripts/boot.gd +++ b/port/scripts/boot.gd @@ -447,6 +447,26 @@ func _play_video(name: String, skippable: bool) -> void: get_tree().quit(2) return print(" -> video %s at %.2f s (%s)" % [name, _elapsed, v["path"]]) + # 🔴 THE MENU BED KEEPS PLAYING UNDER THE MOVIE, AND NOBODY DECIDED THAT. + # + # `MenuAudio.stop_bed()` exists and is called from nowhere, so the music + # started on the main menu runs through the cutscene and on past it. That is + # an UNMADE DECISION, not a choice: the movie carries its own music and + # effects, so the port emits two unrelated music tracks at once, measured at + # r=0.42 for the bed inside the movie's own window (docs/port/DECISIONS.md). + # + # It is NOT silenced here, deliberately. PORT-MISSION's rule is to leave an + # unmeasured detail PLAINLY WRONG rather than plausibly invented, and this is + # the textbook case: music over a cutscene is wrong in a way any listener + # catches in one second, whereas stopping it would sound perfectly right and + # be a guess about the game nobody has watched. The audible version gets + # fixed; the plausible version ships forever. + # + # So it says so instead. Announcing the gap before opening it is what + # `skipped_chain` already does for NEW GAME. + if audio.bed_playing(): + print(" 🔴 the menu bed is STILL PLAYING under this movie -- unmeasured,") + print(" left audible on purpose (BLOCKED.md: does menu music duck?)") var stream := VideoStreamTheora.new() stream.file = v["path"] diff --git a/port/scripts/menu_audio.gd b/port/scripts/menu_audio.gd index 47e335db..7bca3419 100644 --- a/port/scripts/menu_audio.gd +++ b/port/scripts/menu_audio.gd @@ -170,12 +170,32 @@ func play_bed(role: String) -> void: _bed.play() +## 🔴 DEAD CODE, and that is the finding rather than a tidiness note. +## +## Nothing in the port calls this. The bed therefore starts when the main menu +## goes live and never stops -- through the cutscene, and on to the title after +## it. Nobody chose that; it is what happens when the only way to stop something +## is a function no caller remembers. +## +## It is the mirror of `ScreenView.skipped`, which was written every frame and +## read by nobody. One is a fact recorded and never surfaced, the other a +## capability provided and never used, and both were invisible for the same +## reason: nothing fails when they are missed. +## +## Kept, not deleted. The day a capture says whether the game's menu music ducks +## under a movie, this is the one line that has to change. func stop_bed() -> void: if _bed != null: _bed.stop() _bed_role = "" +## Is the music bed sounding right now? Used by the boot to ANNOUNCE that it is +## still playing under a movie, rather than to stop it. +func bed_playing() -> bool: + return _bed != null and _bed.playing + + ## What the audio server is actually doing, for a run's write-up. ## ## `docs/port/AUDIO-VERIFICATION.md`: "recorded under a dummy driver" is a