Read the analysis cache before refusing a pass, and own the cache root

Opening a recording while the session that recorded it was still live never reached
``stored_result()``, so the panel reported no result over a recording whose result was on
disk. The guard now follows the cache read, results move to the app's derived-data root
(swept at startup, the old in-recording root ignored), and the panel states which of the
four no-result states it is in, with the pass's own reason.
Verified: apps/studio 462/0/18, shared 431/0/1, autocal 358, ui_check 628/0, both gates
clean, real-GL snapshots per state.
This commit is contained in:
ykcheungab
2026-10-04 16:53:50 +08:00
parent 1aa454311f
commit a92a2ba237
14 changed files with 1138 additions and 170 deletions
+37
View File
@@ -121,6 +121,43 @@ def recordings_dir() -> Path:
return path
#: Directory name of the product's per-user data, under the OS's own root for it.
DERIVED_DIR_NAME = "OrisysStudio"
#: Subdirectory holding the offline analysis results.
ANALYSIS_CACHE_DIRNAME = "analysis-cache"
def derived_data_dir() -> Path:
"""The OS-correct per-user root for **derived** (rebuildable) data.
Windows: ``%LOCALAPPDATA%\\OrisysStudio`` (falling back to
``%USERPROFILE%\\AppData\\Local`` when the variable is unset — a service or a
stripped environment, where the fallback is still the right directory). Everywhere
else: ``$XDG_CACHE_HOME/OrisysStudio``, or ``~/.cache/OrisysStudio``.
Deliberately *not* :func:`outputs_dir`: in a packaged build that is the EXE's own
directory, and it holds the recordings. Anything the app can rebuild belongs in the
user's own derived-data area, where a reinstall cannot destroy it and where writing
it needs no permission on the installation.
"""
name = DERIVED_DIR_NAME
if os.name == "nt":
local = os.environ.get("LOCALAPPDATA", "").strip()
base = (
Path(local)
if local
else Path(os.environ.get("USERPROFILE", str(Path.home()))) / "AppData" / "Local"
)
return base / name
cache = os.environ.get("XDG_CACHE_HOME", "").strip()
return (Path(cache) if cache else Path.home() / ".cache") / name
def analysis_cache_dir() -> Path:
"""Where the offline analysis results live: the app's own root, never a recording."""
return derived_data_dir() / ANALYSIS_CACHE_DIRNAME
def preference_path() -> Path:
return app_root() / "preference.json"