local M = {}
-- versions.lua
-- Module for version checking according to LMCP contract

-- Both versions are supported. The old version (2025-06-18) is retained
-- for backward compatibility, while the new version (2026-07-28) is added.
-- Dual protocol (old + new) is a later phase.
M.SUPPORTED = {'2025-06-18', '2026-07-28'}

--- Checks whether a version is supported.
-- @param version The version to check (string or nil)
-- @return boolean true if supported, otherwise false
-- @return table|nil error details if not supported
function M.check(version)
    -- (a) version == nil or '' -> true, nil
    if version == nil or version == '' then
        return true, nil
    end

    -- (b) exact match in M.SUPPORTED -> true, nil
    for _, supported_version in ipairs(M.SUPPORTED) do
        if version == supported_version then
            return true, nil
        end
    end

    -- (c) everything else -> false, { code = -32022, data = { supported = <copy> } }
    --
    -- COPY, not M.SUPPORTED itself. Previously the module table leaked out:
    -- a caller that keeps the error object and err.data.supported[1]
    -- overwrites, changes the module's list for EVERY subsequent
    -- call -- demonstrated on 2026-08-09: after
    -- e.data.supported[1] = 'CAPTURED' check('2025-06-18') is false and
    -- check('CAPTURED') is true. Contract rule 5 ('A call must not shift the list of
    -- the next') was thereby broken, and test 5 did not see it
    -- because it never writes over the returned reference.
    -- As long as no one called the module, this was theoretical. Since it is attached to
    -- initialize, it is reachable.
    local copy = {}
    for i = 1, #M.SUPPORTED do
        copy[i] = M.SUPPORTED[i]
    end
    return false, {
        code = -32022,
        data = {
            supported = copy
        }
    }
end

-- No new globals, no side effects, M.SUPPORTED is not modified

return M
