From 429aafb6ce460b555503e62911ec4a709bfaa47e Mon Sep 17 00:00:00 2001 From: Patryk Gensch <43010113+patryk025@users.noreply.github.com> Date: Fri, 19 Jun 2026 00:07:18 +0200 Subject: [PATCH] feat: enhance compatibility table with file name handling and UI updates --- README.md | 6 ++++-- ams/api/static/index.html | 6 ++++-- ams/compat.py | 15 ++++++++++++++- tests/test_compat.py | 17 +++++++++++++++++ 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c0a8300..245eed2 100644 --- a/README.md +++ b/README.md @@ -219,7 +219,9 @@ która gra wiezie którą bibliotekę. Haczyk: ta sama nazwa może wystąpić w nie być tym samym silnikiem. Dlatego w obrębie jednej nazwy klastrujemy **warianty po powierzchni silnika** (te same zbiory tożsamości co `diff`/`similarity` — kompilator-agnostyczne), a każdy wariant inny niż referencyjny (`A`) dostaje **gwiazdkę** `*` z deltą *czym* się różni. Byte-różnice -z rekompilacji nie generują gwiazdki — liczy się API skryptowe. +z rekompilacji nie generują gwiazdki — liczy się API skryptowe. Prefiks `_` doklejany do +nazwy pliku przy składowaniu (np. `333ab0c4_PIKLIB8.dll`) jest **obcinany przed grupowaniem**, więc +wszystkie kopie `PIKLIB8.dll` lądują w jednym wierszu (pełna nazwa pliku zostaje w polu `file` JSON-a). ```bash # z plików snapshot (bez DB/serwera); Label= ustawia kolumnę-grę @@ -236,7 +238,7 @@ curl -OJ "http://127.0.0.1:8000/compat?format=md" # → compat.md curl -OJ "http://127.0.0.1:8000/compat?format=json" # → compat.json (grupy + warianty + diffy) ``` -W UI: przycisk **⬇ kompat** w panelu *Gry / wersje*. Markdown to macierz `biblioteka × gra` +W UI: przyciski **⬇ md** / **⬇ json** w panelu *Gry / wersje*. Markdown to macierz `biblioteka × gra` (`✓` = obecna; `A`/`B*`/… gdy nazwa ma kilka wariantów powierzchni) plus sekcja *Warianty* z przypisem: dla każdego rozbieżnego wariantu overlap % i `types/methods/events/fields +N/-N/~N` względem referencyjnego. diff --git a/ams/api/static/index.html b/ams/api/static/index.html index 05b13c7..8f20b57 100644 --- a/ams/api/static/index.html +++ b/ams/api/static/index.html @@ -17,8 +17,10 @@
Gry / wersje - ⬇ kompat + ⬇ md + ⬇ json
diff --git a/ams/compat.py b/ams/compat.py index 81c2940..3f43de9 100644 --- a/ams/compat.py +++ b/ams/compat.py @@ -17,6 +17,7 @@ from __future__ import annotations import hashlib import json +import re from collections import Counter from dataclasses import dataclass from datetime import datetime, timezone @@ -77,8 +78,19 @@ def _vs_reference(reference: Snapshot, variant: Snapshot) -> dict[str, Any]: # --- table builder ----------------------------------------------------------------------------- +# Stored binaries are prefixed with the first 8 hex of their sha256 to keep filenames unique on +# disk (e.g. ``333ab0c4_PIKLIB8.dll``). That prefix is per-file, so it must be stripped before +# grouping — otherwise every copy of PIKLIB8.dll lands in its own row and nothing ever clusters. +_HASH_PREFIX = re.compile(r"^[0-9a-fA-F]{8}_") + + +def library_name(raw: str) -> str: + """The display/grouping name: the stored binary name with any ``_`` prefix removed.""" + return _HASH_PREFIX.sub("", raw) + + def _library_name(snap: Snapshot) -> str: - return snap.binary.get("name") or "?" + return library_name(snap.binary.get("name") or "?") def _variant_id(index: int) -> str: @@ -115,6 +127,7 @@ def _build_library(name: str, entries: list[Entry]) -> dict[str, Any]: members = [ { "game": e.game, + "file": e.snapshot.binary.get("name"), # stored name, incl. the _ prefix "engine": e.snapshot.binary.get("engine"), "compiler": e.snapshot.binary.get("compiler"), "sha256": e.snapshot.binary.get("sha256"), diff --git a/tests/test_compat.py b/tests/test_compat.py index 723479e..9c0ea0e 100644 --- a/tests/test_compat.py +++ b/tests/test_compat.py @@ -77,6 +77,23 @@ def test_divergent_surface_raises_asterisk(): assert lib["cells"]["Game C"]["diverges"] is True +def test_hash_prefix_is_stripped_for_grouping(): + # stored names carry a per-file _ prefix; copies must still group under one library row + t = compatibility_table([ + Entry("Game A", _snap("333ab0c4_PIKLIB8.dll", ["SHOW", "HIDE"])), + Entry("Game B", _snap("8dc0165d_PIKLIB8.dll", ["SHOW", "HIDE"])), + Entry("Game C", _snap("bba62d83_PIKLIB8.dll", ["SHOW", "HIDE", "PAUSE"])), + ]) + assert len(t["libraries"]) == 1 + lib = t["libraries"][0] + assert lib["name"] == "PIKLIB8.dll" # prefix gone from the display name + assert lib["variant_count"] == 2 # A,B identical → reference; C diverges → asterisk + assert lib["cells"]["Game C"]["diverges"] is True + # the original stored filename is preserved per member for correlation + files = {m["file"] for v in lib["variants"] for m in v["members"]} + assert "333ab0c4_PIKLIB8.dll" in files + + def test_grouping_is_case_insensitive_keeps_common_spelling(): t = compatibility_table([ Entry("Game A", _snap("Piklib8.dll", ["SHOW"])),