Module:Sandbox/Vergir: Difference between revisions

From The Deadlock Wiki
Jump to navigation Jump to search
Vergir (talk | contribs)
Diagnostic: check InfoboxHero render determinism (with help from vergir-bot LLM)
Tag: Replaced
Vergir (talk | contribs)
Temporary probe: dump SpiritScaling entries from Data:HeroData.json (with help from vergir-bot LLM)
Line 1: Line 1:
-- TEMPORARY diagnostic.
-- TEMPORARY probe. Dumps every SpiritScaling entry in Data:HeroData.json,
-- Renders heroes through the LIVE Module:InfoboxHero twice each and compares the
-- together with the label resolution paths available for each stat key.
-- two outputs, to establish whether rendering is deterministic at all.
-- {{#invoke:Sandbox/Vergir|dump}}
-- {{#invoke:Sandbox/Vergir|selfdiff}}
local p = {}
local p = {}


local infobox = require('Module:InfoboxHero')
local heroes_data = mw.loadJsonData("Data:HeroData.json")
local attributes_data = mw.loadJsonData("Data:AttributeData.json")
local lang_module = require('Module:Lang')
local dictionary_module = require('Module:Dictionary')
local hero_data_module = require('Module:HeroData')


local SAMPLE_HEROES = {
local function attr_label_key(stat)
'hero_atlas',
for _, category in pairs(attributes_data) do
'hero_viscous',
if category[stat] ~= nil then
'hero_haze',
return category[stat]["label"], category[stat]["postfix"]
'hero_werewolf',
end
'hero_targetdummy',
}
 
-- Byte offset of the first difference, or nil when the strings are equal.
local function first_diff(a, b)
local limit = math.min(#a, #b)
for i = 1, limit do
if a:sub(i, i) ~= b:sub(i, i) then return i end
end
end
if #a ~= #b then return limit + 1 end
return nil, nil
return nil
end
end


function p.selfdiff(frame)
function p.dump(frame)
local keys = {}
local keys = {}
if frame.args[1] and frame.args[1] ~= '' then
for hero_key, hero_data in pairs(heroes_data) do
for key in string.gmatch(frame.args[1], '[^,%s]+') do
local scaling = hero_data["SpiritScaling"]
table.insert(keys, key)
if scaling ~= nil and next(scaling) ~= nil then
table.insert(keys, hero_key)
end
end
else
keys = SAMPLE_HEROES
end
end
table.sort(keys)


local out = {}
local out = {}
local mismatches = 0
local stats_seen = {}
 
for _, hero_key in ipairs(keys) do
for _, hero_key in ipairs(keys) do
local child = frame:newChild{ args = { key = hero_key } }
local hero_data = heroes_data[hero_key]
local a = tostring(infobox.render(child))
local stat_keys = {}
local b = tostring(infobox.render(child))
for stat in pairs(hero_data["SpiritScaling"]) do
local at = first_diff(a, b)
table.insert(stat_keys, stat)
if at ~= nil then
stats_seen[stat] = true
mismatches = mismatches + 1
local from = math.max(1, at - 50)
local to = at + 50
table.insert(out, '* <code>' .. hero_key .. '</code> differs at byte ' .. at ..
' (len ' .. #a .. ' vs ' .. #b .. ')')
table.insert(out, '** A: <code>' .. mw.text.nowiki(a:sub(from, to)) .. '</code>')
table.insert(out, '** B: <code>' .. mw.text.nowiki(b:sub(from, to)) .. '</code>')
end
end
table.sort(stat_keys)
local parts = {}
for _, stat in ipairs(stat_keys) do
local base = hero_data_module.get_stat(hero_data, stat)
table.insert(parts, stat .. '=' .. tostring(hero_data["SpiritScaling"][stat]) ..
' (base ' .. tostring(base) .. ')')
end
table.insert(out, '* <code>' .. hero_key .. '</code> ' .. tostring(hero_data["Name"]) ..
' [dev=' .. tostring(hero_data["InDevelopment"]) ..
' disabled=' .. tostring(hero_data["IsDisabled"]) ..
' labs=' .. tostring(hero_data["InHeroLabs"]) ..
' selectable=' .. tostring(hero_data["IsSelectable"]) .. ']: ' ..
table.concat(parts, ', '))
end
local stat_list = {}
for stat in pairs(stats_seen) do table.insert(stat_list, stat) end
table.sort(stat_list)
table.insert(out, '')
table.insert(out, 'Label resolution per stat:')
for _, stat in ipairs(stat_list) do
local label_key, postfix_key = attr_label_key(stat)
local lang_str = label_key and lang_module.get_string(label_key) or ''
local postfix_str = postfix_key and lang_module.get_string(postfix_key) or ''
local dict_str = dictionary_module.translate(stat)
table.insert(out, '* <code>' .. stat .. '</code> attr_label=<code>' ..
tostring(label_key) .. '</code> lang="' .. tostring(lang_str) ..
'" postfix="' .. tostring(postfix_str) ..
'" dict="' .. tostring(dict_str) .. '"')
end
end


return 'Same module rendered twice per hero, heroes: ' .. #keys ..
return table.concat(out, '\n')
'\n\nNon-deterministic: ' .. mismatches .. '\n' .. table.concat(out, '\n')
end
end


return p
return p

Revision as of 14:01, 11 August 2026

Documentation for this module may be created at Module:Sandbox/Vergir/doc

-- TEMPORARY probe. Dumps every SpiritScaling entry in Data:HeroData.json,
-- together with the label resolution paths available for each stat key.
-- {{#invoke:Sandbox/Vergir|dump}}
local p = {}

local heroes_data = mw.loadJsonData("Data:HeroData.json")
local attributes_data = mw.loadJsonData("Data:AttributeData.json")
local lang_module = require('Module:Lang')
local dictionary_module = require('Module:Dictionary')
local hero_data_module = require('Module:HeroData')

local function attr_label_key(stat)
	for _, category in pairs(attributes_data) do
		if category[stat] ~= nil then
			return category[stat]["label"], category[stat]["postfix"]
		end
	end
	return nil, nil
end

function p.dump(frame)
	local keys = {}
	for hero_key, hero_data in pairs(heroes_data) do
		local scaling = hero_data["SpiritScaling"]
		if scaling ~= nil and next(scaling) ~= nil then
			table.insert(keys, hero_key)
		end
	end
	table.sort(keys)

	local out = {}
	local stats_seen = {}
	for _, hero_key in ipairs(keys) do
		local hero_data = heroes_data[hero_key]
		local stat_keys = {}
		for stat in pairs(hero_data["SpiritScaling"]) do
			table.insert(stat_keys, stat)
			stats_seen[stat] = true
		end
		table.sort(stat_keys)
		local parts = {}
		for _, stat in ipairs(stat_keys) do
			local base = hero_data_module.get_stat(hero_data, stat)
			table.insert(parts, stat .. '=' .. tostring(hero_data["SpiritScaling"][stat]) ..
				' (base ' .. tostring(base) .. ')')
		end
		table.insert(out, '* <code>' .. hero_key .. '</code> ' .. tostring(hero_data["Name"]) ..
			' [dev=' .. tostring(hero_data["InDevelopment"]) ..
			' disabled=' .. tostring(hero_data["IsDisabled"]) ..
			' labs=' .. tostring(hero_data["InHeroLabs"]) ..
			' selectable=' .. tostring(hero_data["IsSelectable"]) .. ']: ' ..
			table.concat(parts, ', '))
	end

	local stat_list = {}
	for stat in pairs(stats_seen) do table.insert(stat_list, stat) end
	table.sort(stat_list)

	table.insert(out, '')
	table.insert(out, 'Label resolution per stat:')
	for _, stat in ipairs(stat_list) do
		local label_key, postfix_key = attr_label_key(stat)
		local lang_str = label_key and lang_module.get_string(label_key) or ''
		local postfix_str = postfix_key and lang_module.get_string(postfix_key) or ''
		local dict_str = dictionary_module.translate(stat)
		table.insert(out, '* <code>' .. stat .. '</code> attr_label=<code>' ..
			tostring(label_key) .. '</code> lang="' .. tostring(lang_str) ..
			'" postfix="' .. tostring(postfix_str) ..
			'" dict="' .. tostring(dict_str) .. '"')
	end

	return table.concat(out, '\n')
end

return p