diff --git a/docs/modding.md b/docs/modding.md index fbff19f9..6c45ef92 100644 --- a/docs/modding.md +++ b/docs/modding.md @@ -158,6 +158,10 @@ local keys, code, message = mod.storage:list(game, "history/quick") local deleted, code, message = mod.storage:delete(game, "history/quick/q0001") ``` +`context` returns `{ engineVersion, gameVersion, playthroughId }`. The engine +version is compatibility metadata; physical launcher-slot and path identity stays +private. + Values must be tables containing serializable data only. Keys are conservative slash-separated segments (letters, digits, `_`, `-`); paths and filesystem handles are never exposed. Writes are staged and decode-verified, reads recover diff --git a/docs/rfcs/0003-playthrough-storage.md b/docs/rfcs/0003-playthrough-storage.md index d95fddb2..96c574e2 100644 --- a/docs/rfcs/0003-playthrough-storage.md +++ b/docs/rfcs/0003-playthrough-storage.md @@ -51,10 +51,11 @@ honors injected test filesystems; it is not exposed on the mod object. Returns: ```lua -{ gameVersion = "red", playthroughId = "..." } +{ engineVersion = "0.9.0", gameVersion = "red", playthroughId = "..." } ``` -or `nil, code, message`. It intentionally omits launcher slot ids and paths. +or `nil, code, message`. `engineVersion` is warning-grade compatibility metadata; +the context intentionally omits launcher slot ids and paths. ### `mod.storage:write(game, key, value)` diff --git a/src/mods/Storage.lua b/src/mods/Storage.lua index d5f3a324..e529106c 100644 --- a/src/mods/Storage.lua +++ b/src/mods/Storage.lua @@ -3,6 +3,7 @@ local SaveData = require("src.core.SaveData") local SaveSerializer = require("src.core.SaveSerializer") +local Version = require("src.core.Version") local Storage = {} Storage.__index = Storage @@ -81,7 +82,11 @@ end function Storage:context(game) local scope, code, message = self:_scope(game) if not scope then return nil, code, message end - return { gameVersion = scope.gameVersion, playthroughId = scope.playthroughId } + return { + engineVersion = Version.engine, + gameVersion = scope.gameVersion, + playthroughId = scope.playthroughId, + } end function Storage:_names(game, key, allowEmpty) diff --git a/tests/modkit/cases/storage.lua b/tests/modkit/cases/storage.lua index 52b0f886..56564c31 100644 --- a/tests/modkit/cases/storage.lua +++ b/tests/modkit/cases/storage.lua @@ -7,6 +7,7 @@ love = love or require("tests.love_stub") local T = require("tests.harness").suite("mod storage") local Loader = require("src.mods.Loader") local Runtime = require("src.mods.Runtime") +local Version = require("src.core.Version") local savedEvents, savedHooks = Runtime.events, Runtime.hooks @@ -90,8 +91,11 @@ end -- Removing scope identity or exposing a mutable private slot id breaks this. local context = alpha:context(current) -T.same(context, { gameVersion = "red", playthroughId = "play-a" }, - "context exposes stable game/playthrough identity only") +T.same(context, { + engineVersion = Version.engine, + gameVersion = "red", + playthroughId = "play-a", +}, "context exposes stable engine/game/playthrough compatibility identity") -- Data-only write/read. The literal expected table is independent of storage. local payload = { format = 1, nested = { money = 1234 }, flags = { a = true } }