diff --git a/schemas/emulator.schema.json b/schemas/emulator.schema.json index 23c3356c..3b6062aa 100644 --- a/schemas/emulator.schema.json +++ b/schemas/emulator.schema.json @@ -912,6 +912,22 @@ "type": "string", "description": "Why source_commit is held on purpose rather than followed. The profile is then judged against its own revision, like one pinned to a superseded tag: comparing it to HEAD says nothing and recaling would repoint its refs at code the build it documents never had." }, + "data_root": { + "type": "object", + "minProperties": 1, + "propertyNames": {"enum": ["android", "ios", "windows", "macos", "linux"]}, + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "required": ["path", "source_ref"], + "properties": { + "path": {"type": "string", "minLength": 1, "description": "The folder as the user finds it on that OS, with the environment variable or home prefix the code expands (%APPDATA%, ~, Android/data/)."}, + "source_ref": {"type": "string", "minLength": 1}, + "note": {"type": "string"} + } + }, + "description": "Per operating system, the folder the app reads its user data from, under which standalone_path destinations sit. Only the systems the app runs on are keyed." + }, "upstream_frozen": { "type": "string", "description": "Why upstream_commit is held on purpose rather than followed: the port vendors that upstream tree, synced to that release, or merged that commit. The upstream view is judged against its own revision and a bump leaves it, the way pin_frozen holds source_commit." diff --git a/tests/test_schema_semantic_gate.py b/tests/test_schema_semantic_gate.py index 6c06b3d0..746d2822 100644 --- a/tests/test_schema_semantic_gate.py +++ b/tests/test_schema_semantic_gate.py @@ -96,3 +96,29 @@ class SemanticManifestValidation(unittest.TestCase): if __name__ == "__main__": unittest.main() + + +try: + import jsonschema +except ImportError: + jsonschema = None + + +@unittest.skipIf(jsonschema is None, "jsonschema unavailable") +class DataRootIsKeyedBySystem(unittest.TestCase): + """AetherSX2 gave Android/data/xyz.aethersx2.android only in its notes: + the site could not print the folder, nor which OS tabs apply.""" + + def _errors(self, value): + schema = json.loads((REPO_ROOT / "schemas/emulator.schema.json").read_text(encoding="utf-8")) + validator = jsonschema.Draft202012Validator(schema["properties"]["data_root"]) + return list(validator.iter_errors(value)) + + def test_a_system_with_its_path_and_reference(self): + self.assertEqual(self._errors({"android": { + "path": "Android/data/xyz.aethersx2.android/files", "source_ref": "a.kt:1"}}), []) + + def test_an_unknown_system_or_a_path_without_reference(self): + self.assertTrue(self._errors({"amiga": {"path": "x", "source_ref": "y"}})) + self.assertTrue(self._errors({"windows": {"path": "%APPDATA%/X"}})) + self.assertTrue(self._errors({})) diff --git a/wiki/profiling.md b/wiki/profiling.md index 420c6336..0e106927 100644 --- a/wiki/profiling.md +++ b/wiki/profiling.md @@ -591,6 +591,7 @@ does not look. | `known_hash_adler32` | expected Adler-32 hash (Dolphin's DSP ROMs). Pair with `adler32_byteswap` when the code hashes 16-bit byte-swapped data | | `adler32_pairs_with`, `adler32_pairs` | the file hashed together with this one and the combinations the code accepts, this file's value first, in table order: Dolphin warns on a DSP ROM pair outside its `known_roms` even when each file passes alone | | `pin_frozen` | why `source_commit` is held on purpose rather than followed. The profile is then judged against its own revision, like one pinned to a superseded tag | +| `data_root` | per operating system (`android`, `ios`, `windows`, `macos`, `linux`), the folder the app reads its user data from, under which `standalone_path` destinations sit: `path` as the user finds it (`Android/data//files`, `%APPDATA%/...`), with the `source_ref` that builds it. Only the systems the app runs on are keyed | | `upstream_frozen` | why `upstream_commit` is held: the port vendors that upstream tree, synced to that release, or merged that commit. The upstream view is read at its own pin and a bump leaves it. Without it, a port that is a GitHub fork of its upstream follows the merge base of the two | | `prose_written_at` | the pin a reader confirmed the prose citations against. When the profile's history shows a text living under several pins, profile_sync takes this one as the revision the text describes, so a bump is no longer refused for a citation already reread. It never overrides a history with a single candidate | | `version_source` | for a project published outside any forge, `{url, pattern}`: the page that announces releases and a regular expression whose first group is the latest version. `profile_sync --check-version` compares it with `core_version`, and `check_freshness --profiles` calls the profile stale when they differ. `no_genuine_copy` names an announced version found only rebuilt or re-signed: the profile stays on the newest unmodified build and is not stale until the page announces a later one |