Takes the port branch up to77320d5e-- the state the human play-tested on 2026-09-02 -- for SOURCE paths only. Not a branch merge: `auto/port-p6-audio` is 366 commits and 938 files, and most of that must not land. WHAT COMES IN (76 files, all human-confirmed working): * the logo splash animation.08ed3dd1found it: `pose_at` ASSIGNED the settle instant instead of clamping to it, so the splash never animated at all -- and the same bug manufactured a passing harness result, because the harness photographed t past the settle. Confirmed by play-test: "cannot notice any obvious difference from the actual game." * gamepad input -- (A)/(B) bound additively (`ui_accept` ships with NO joypad binding), stick latched with hysteresis at the game's own 61% digitise threshold. This is what made (A), video-skip and Extras work at all. * menu navigation and flow, menu audio, the exporter, the authored declarations, and 23 verification tools under tools/port/. WHAT IS DELIBERATELY LEFT ON THE BRANCH: * everything afterc0ae460a-- the F5/F6 title-timing investigation, whose own tip commit calls itself a "hand-off for one-minute human checks". Unchecked by definition; it goes through the new review gate like anything else. * the OPTIONS menu work of 2026-09-03. Real, probably good, NOT play-tested. * the F1 repeat mechanism, which its own commit calls "deliberately inert". WHAT MUST NOT LAND, AND WHY THE .gitignore CHANGED: 545 MB of extracted game content was committed on that branch -- 850 sprite, audio and transcoded video files under `export-probe/` and `export-probe2/`, plus 246 MB of loose .wav and .tsv at the repo root. This repository's own rule, in this file, is "never game content". The rule was not missing. It was written, and it was tightened on that very branch, with a careful comment explaining why BOTH `export/` and `data/base/` had to be listed -- while the exporter was writing to a third name that nobody had thought to list. Enumerating names is the thing that failed. So the ignore rules now describe the SHAPE: any top-level `export*/`, game media by extension, and loose capture output at the root. Verified both ways -- it catches all four offenders and ignores nothing currently tracked. Verified: `cargo check --workspace` clean; all nine GDScript files parse in project context, with a positive control (an injected syntax error is detected, 3 lines) so the clean result means something. `tools/port/check-all` was NOT run -- it needs the container, the export tree and a display.
159 lines
7.3 KiB
Markdown
159 lines
7.3 KiB
Markdown
# Running the port
|
|
|
|
**P5's gate is *"a human clicks through it"*, and until now there was no page
|
|
telling a human how.** The commands existed — in `boot.gd`'s header comment and
|
|
scattered through a twelve-thousand-line `DECISIONS.md`. A capability that lives
|
|
only in the record is, to the person who needs it, absent.
|
|
|
|
Everything below has been run. Where a number is quoted it was measured in this
|
|
container, and where the container distorts it that is said rather than left for
|
|
the reader to discover.
|
|
|
|
## 1. Build the asset tree
|
|
|
|
The Godot project reads `export/`, never the disc.
|
|
|
|
```bash
|
|
cargo run --release -p sylpheed-export -- export --disc /disc --out export
|
|
```
|
|
|
|
Roughly four minutes, most of it transcoding two movies. It **rewrites `export/`
|
|
wholesale** — never hand-edit anything in there; hand-written decisions live in
|
|
`authored/` beside it, and survive a re-export.
|
|
|
|
## 2. The P5 walk, from a cold start
|
|
|
|
```bash
|
|
godot --path port -- --boot --play
|
|
```
|
|
|
|
This is the one a human should judge. It boots the way the game does — two
|
|
splashes, the `ADV` intro, the title — hands over to the menu on Ⓐ, and then
|
|
**stays live and waits for input**.
|
|
|
|
| you press | what should happen |
|
|
|---|---|
|
|
| Ⓐ on the title | the main menu opens on **NEW GAME** |
|
|
| ⬆ / ⬇ | one item, wrapping at both ends |
|
|
| ⬅ / ➡ | **nothing** — measured, and implemented as an explicit no-op |
|
|
| Ⓐ on **EXTRAS** | the EXTRAS submenu, opening on **MISSION SELECT** |
|
|
| Ⓑ in EXTRAS | back to the main menu, **on the item you left** |
|
|
| Ⓑ on the main menu | back to the title |
|
|
| Ⓐ on the title again | the menu, **still on the item you left** |
|
|
|
|
That last row is the one worth checking deliberately: the main menu **remembers
|
|
its cursor**, and every submenu **resets** to its own opening item. Both are
|
|
measured, and they disagree on purpose.
|
|
|
|
⏱ **The intro is ~157 s.** To skip straight to the menu:
|
|
|
|
```bash
|
|
godot --path port -- --menu=main_menu
|
|
```
|
|
|
|
and to drive it unattended:
|
|
|
|
```bash
|
|
godot --path port -- --menu=main_menu --script=down,down,down,down,accept,cancel
|
|
```
|
|
|
|
🔴 **This example used to say `down,down,accept,cancel`, and it walked the wrong
|
|
path.** Two ⬇ from the opening item lands on **`TUTORIAL`**, whose destination this
|
|
export does not carry — so the example exercised a *not-carried* message and
|
|
returned, never opening a submenu at all. **`EXTRAS` is the fifth item**, so it
|
|
takes four. The one submenu P5's gate rests on was the one the runbook's own
|
|
command did not reach. Verified 2026-08-31 by running both.
|
|
|
|
🔴 `--script` **without** `--play` or `--menu` refuses and says so. It used to
|
|
parse, be stored, and do nothing.
|
|
|
|
## 3. What is knowingly missing — not bugs
|
|
|
|
Four of the five main-menu destinations are **measured but not in this export**:
|
|
they live in other archives (`GP_SAVE_LOAD`, `GP_OPTIONS`, …). Pressing Ⓐ on them
|
|
prints what it would have opened and why it cannot:
|
|
|
|
```
|
|
(LOAD GAME) opens a screen this export does not carry:
|
|
The save-slot list is GP_SAVE_LOAD, not in this export. Destination MEASURED.
|
|
```
|
|
|
|
**EXTRAS is the only Ⓐ-into-a-submenu this milestone can walk**, which is why the
|
|
P5 gate rests on it.
|
|
|
|
`NEW GAME` is a deliberate gap of a different kind: the real chain is
|
|
NEW GAME → DIFFICULTY → SELECT DATA → the `S00A` movie, and the port **jumps to
|
|
the movie**, printing the two screens it skipped. That is a gap, stated out loud;
|
|
nobody should read the port's behaviour there as the game's.
|
|
|
|
## 4. What this container distorts
|
|
|
|
* **No GPU.** 720p Theora decodes **+6.7 % … +6.9 % slower than real time** here
|
|
(5 runs, both movies, on a quiet box). The boot's printed seconds carry that
|
|
deficit. It is a property of the machine, not of the port.
|
|
* **No sound card.** Godot falls back to a dummy driver, so **you will hear
|
|
nothing**. The audio is present and measurable —
|
|
`docs/port/AUDIO-VERIFICATION.md` answers every audio question without a
|
|
device, and `tools/port/verify-menu-audio` asserts it — but *"I heard it"* is
|
|
not available in here.
|
|
* **A leaked-object warning at exit** is engine-side, not the port's. Measured:
|
|
releasing every reference the port owns moves the count from 8 to 8.
|
|
|
|
## 5. Modding
|
|
|
|
`data/mods/` shadows `export/` by path. Each override is announced as it is read,
|
|
and at the end of a run any file that **can never apply** is listed:
|
|
|
|
```
|
|
mod: sprites/title/main_menu/ptbase.png <- data/mods/...
|
|
mods: 1 file(s) in data/mods can shadow NOTHING -- no such path in the export:
|
|
inert: sprites/title/TYPO_menu/pteff05.png
|
|
```
|
|
|
|
A file whose path exists in the export but was simply not read this run is **not**
|
|
listed. See `docs/port/MODDING.md` for the five rules the asset tree keeps.
|
|
|
|
## 6. Where the work is, and what P5's gate is waiting on
|
|
|
|
**P5's gate is the only one that needs a person, and it is not waiting on code.**
|
|
|
|
Everything above runs from `auto/port-p6-audio`.
|
|
|
|
🔴 **This section used to quote counts — "256 commits ahead, 58 files" — and they
|
|
were stale the moment they were committed, because committing them incremented
|
|
the count.** By the time anyone read it, it said 256 and the answer was 258. A
|
|
number written into a document meant to inform a decision **decays with every
|
|
commit either agent makes**, and the Decoder hit the same thing in their own
|
|
merge-state page one message after recording the class.
|
|
|
|
**So what follows are the invariants, which do not move, and the commands to
|
|
re-derive anything that does.**
|
|
|
|
| invariant | check | **passes when** |
|
|
|---|---|---|
|
|
| `main` is an **ancestor** of this branch — a fast-forward, nothing to resolve | `git merge-base --is-ancestor origin/main HEAD; echo $?` | prints **`0`**. ⚠️ The command itself prints **nothing** on success — without the `echo` a reader cannot tell success from failure |
|
|
| `main` is an ancestor of the Decoder's branch too | `git merge-base --is-ancestor origin/main origin/auto/build-ordinal-audit; echo $?` | prints **`0`**, same caveat |
|
|
| the two change sets touch **zero files in common** | `comm -12 <(git diff --name-only origin/main...HEAD \| sort) <(git diff --name-only origin/main...origin/auto/build-ordinal-audit \| sort) \| wc -l` | prints **`0`** |
|
|
| merging both produces **no conflicts** | `git merge-tree --write-tree HEAD origin/auto/build-ordinal-audit \| wc -l` | prints **`1`** — one line is the tree id; conflicts would follow it. **Read-only: this merges nothing** |
|
|
|
|
**Last run here: `0`, `0`, `0`, `1`.** A command published without a pass
|
|
condition is half a check — the reader gets a number and no way to know whether it
|
|
is the right one — so each row states what the right one is.
|
|
|
|
📌 **So the sentence is not "N commits behind", which sounds like something to
|
|
schedule. It is: two fast-forwards over disjoint file sets, mergeable in either
|
|
order with zero conflicts.** Counts if you want them:
|
|
`git rev-list --count origin/main..HEAD`.
|
|
|
|
### What a person is actually being asked to do
|
|
|
|
1. `godot --path port -- --boot --play`, then walk §2's table.
|
|
2. Say whether it behaves as described. **Not whether it matches the game** —
|
|
that comparison is the oracle's job and is already asserted by
|
|
`tools/port/check-all`.
|
|
3. If it does, P5's gate is met and nothing else is blocking P6, which asserts its
|
|
own audio and has no human step.
|
|
|
|
⚠️ **You will hear nothing** (§4), and the intro takes ~157 s. `--menu=main_menu`
|
|
skips straight to the part being judged.
|