From 02edf40d8f62c111113d4aefd6a431475661f793 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sat, 5 Sep 2026 10:17:37 +0200 Subject: [PATCH] fix: let the fallback mapping reach the largest file cited openbor.c is 55k lines at the pin and 57k at HEAD, over a ceiling of 40k, so its ref reported CHANGED with nothing to act on: the mapping was never attempted. Diffing that pair takes nine seconds, and the fallback only runs once exact anchoring has failed, which is rare. The ceiling now sits above it and still stops a pathological pair from stalling a sweep of every profile. savesettings moved from 2675 to 2940 and the range maps cleanly. --- emulators/openbor.yml | 16 ++++++++-------- scripts/profile_sync.py | 7 ++++++- tests/test_profile_sync.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/emulators/openbor.yml b/emulators/openbor.yml index 53226b81..8b1d6d01 100644 --- a/emulators/openbor.yml +++ b/emulators/openbor.yml @@ -4,7 +4,7 @@ core_classification: game_engine source: "https://github.com/DCurrent/openbor" upstream: "https://github.com/DCurrent/openbor" profiled_date: "2026-08-12" -source_commit: "0ece95d1c113c1ce86f2da826b3c25b521ee116d" +source_commit: "9d81480f8481fbb9e76b0b5f2a5dfa408376761a" core_version: "4.0 Build 7949" display_name: "OpenBOR Game Engine" cores: @@ -35,18 +35,18 @@ notes: | such argument the built in menu lists Paks/ and the player picks one (engine/sdl/sdlport.c:25,124-135, engine/sdl/menu.c:172-203,802). packfile_supported accepts any name containing .pak and skips menu.pak - (engine/source/gamelib/packfile.c:1577-1584). + (engine/source/gamelib/packfile.c:1595-1602). Everything read for a running game comes out of that module. buffer_pakfile tries the real filesystem first through fopen, then the same path inside the - archive (engine/openbor.c:921-965,969-1018), so data/models.txt, + archive (engine/openbor.c:935-979,983-1032), so data/models.txt, data/levels.txt, data/video.txt, data/menu.txt, the scene scripts and the sprites and sounds under data/ resolve either from an unpacked data/ directory beside the binary (engine/source/gamelib/packfile.c:781-810) or from the pak. Four names take precedence over their in-pak copy when they exist on disk: translation/translation.txt and translation/menu.txt over data/translation.txt - (engine/source/gamelib/translation.c:102-106, engine/openbor.c:5975,53240), - saves/lifebar.txt over data/lifebar.txt (engine/openbor.c:4965-4972), and on + (engine/source/gamelib/translation.c:102-106, engine/openbor.c:6744,54707), + saves/lifebar.txt over data/lifebar.txt (engine/openbor.c:5734-5741), and on Android Saves//touch.txt then Saves/touch.txt over data/touch.txt (engine/android/app/jni/openbor/video.c:210-218). Each holds text or a control layout written for one module. The engine/translation.txt copied into the @@ -67,12 +67,12 @@ notes: | Files the engine writes rather than expects: Paks, Saves, Logs and ScreenShots are created at startup when missing (engine/sdl/sdlport.c:30-33,119-122), settings and progress land in Saves as .cfg, .sav, .hi, .scr and .inp - alongside default.cfg (engine/source/utils.c:284-312, - engine/openbor.c:2675-3040), and the viewer reads back Logs/OpenBorLog.txt and + alongside default.cfg (engine/source/utils.c:324-352, + engine/openbor.c:2940-3482), and the viewer reads back Logs/OpenBorLog.txt and Logs/ScriptLog.txt (engine/source/utils.c:47-62, engine/sdl/menu.c:652-700). paks/logoff.txt is a marker whose existence alone skips the startup logo, so the player creates it empty (engine/sdl/menu.c:707-716). Module script can open any path it names through openfilestream - (engine/openborscript.c:10505-10600). + (engine/openborscript.c:10573-10668). files: [] diff --git a/scripts/profile_sync.py b/scripts/profile_sync.py index 2b029f00..b427e170 100644 --- a/scripts/profile_sync.py +++ b/scripts/profile_sync.py @@ -45,7 +45,12 @@ WIDEN_STEPS = (0, 3, 6, 12, 25, 50) # A 30k-line driver diffs in about five seconds, and the biggest files the # corpus cites sit just above that. The cap stays as a guard against # pathological inputs, not as a limit on real source files. -MAX_MATCH_LINES = 40000 +# The fallback mapping is a full sequence diff, and it only runs once exact +# anchoring has failed, which is rare. openbor.c is the largest file any +# profile cites, 55k lines against 57k, and diffing the pair takes nine +# seconds; the ceiling sits above it so that one resolves, and still stops a +# pathological pair from stalling a sweep of every profile. +MAX_MATCH_LINES = 60000 PIN = "pin" HEAD = "head" diff --git a/tests/test_profile_sync.py b/tests/test_profile_sync.py index 659af9e3..9ed005f9 100644 --- a/tests/test_profile_sync.py +++ b/tests/test_profile_sync.py @@ -2160,6 +2160,34 @@ class TestWriteDryRun(unittest.TestCase): self.assertEqual(self.path.read_text(), before) +class TestLargeFileCeiling(unittest.TestCase): + """The fallback mapping bails above a ceiling, and it sits high enough. + + openbor.c is the largest file any profile cites, 55k lines against 57k + at HEAD, and the ref that mattered mapped only once the ceiling cleared + it. The guard stays so a pathological pair cannot stall a sweep. + """ + + def test_a_pair_over_the_ceiling_is_not_diffed(self): + big = ["x"] * (profile_sync.MAX_MATCH_LINES + 1) + result = profile_sync._map_changed(big, big, 1, 2) + self.assertEqual(result.status, "CHANGED") + self.assertIn("over", result.reason) + + def test_a_pair_under_the_ceiling_is_mapped(self): + pin = ["a", "subject", "b"] + head = ["pad", "pad", "a", "subject", "b"] + result = profile_sync._map_changed(pin, head, 2, 2) + self.assertIsNotNone(result.start, "a small pair has to be diffed") + self.assertNotIn("over", result.reason or "") + + def test_the_ceiling_clears_the_largest_file_any_profile_cites(self): + self.assertGreater( + profile_sync.MAX_MATCH_LINES, 57000, + "openbor.c is 57k lines at HEAD and its ref has to map", + ) + + class TestRebaseWaitsForThePin(unittest.TestCase): """Recaling refs the pin cannot follow manufactures the desync.