From 357e7554a5989a02555c28677e3d4fb922be9175 Mon Sep 17 00:00:00 2001 From: Calic Date: Sun, 14 Jun 2026 19:29:46 +0200 Subject: [PATCH] fix: resolve_locale de-dups sources and rejects malformed tables Two silent-fail scenarios closed: - sources={c, c} would double-count in can_craft then partial- consume in craft. resolve_locale now de-duplicates by handle identity, preserving first-occurrence order. - {sink=x} without sources would wrap the table as Form-1 and crash deep inside inventory-list. resolve_locale now loud- errors with "locale table must contain 'sources' field" before reaching the bw-compat fallback. Helper comment translated to English per code-language convention. Co-Authored-By: Claude Opus 4.7 (1M context) --- init.lua | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/init.lua b/init.lua index 64d48e9..48673b5 100644 --- a/init.lua +++ b/init.lua @@ -76,9 +76,9 @@ local function shallow_copy(t) return out end --- Locale-Resolver: akzeptiert entity_handle (bw-compat) ODER table --- {sources={...}, sink=...}. Returns immer Form-2 mit validierten --- Feldern. Loud-Error bei kaputter Form-2. +-- Locale resolver: accepts entity_handle (bw-compat) OR table +-- {sources={...}, sink=...}. Always returns Form-2 with validated +-- fields. Loud-error on malformed Form-2. local function resolve_locale(locale, fn_name) -- Form 2: explicit table if type(locale) == "table" and locale.sources ~= nil then @@ -92,7 +92,27 @@ local function resolve_locale(locale, fn_name) "crafting.%s: locale.sink must not be nil", fn_name), 3) end - return locale + -- De-duplicate sources by identity, preserving first-occurrence order. + -- A caller building sources programmatically (e.g. {workbench_buffer, + -- player_backpack} where both alias the same entity) should not have + -- count_by_template double-count nor craft silent-fail. + local seen, deduped = {}, {} + for _, s in ipairs(locale.sources) do + if not seen[s] then + seen[s] = true + deduped[#deduped + 1] = s + end + end + return { sources = deduped, sink = locale.sink } + end + -- Form 2 malformed: a table that's not Form-2 (no sources key) is almost + -- certainly a caller typo. Loud-error explicitly instead of silently + -- falling through to the Form-1 bw-compat path (which would then crash + -- deep inside inventory-list with an opaque error). + if type(locale) == "table" then + error(string.format( + "crafting.%s: locale table must contain 'sources' field", + fn_name), 3) end -- Form 1 (bw-compat): bare entity_handle if locale == nil then