Skip to content

Commit 6c1e80d

Browse files
committed
feat: infer game labels from legacy issue text in relabel
When no structured Game form section is present, infer game labels/scripts deterministically from title/body using serverlist alias mappings. Apply this to both issue-ai-maintenance and backfill to improve historical game labeling without relying on AI.
1 parent 3911c20 commit 6c1e80d

1 file changed

Lines changed: 51 additions & 0 deletions

File tree

.github/workflows/labeler.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,24 @@ jobs:
157157
.filter(Boolean);
158158
}
159159
160+
function findGamesFromText(text, gameAliasToLabel, gameAliasToScript) {
161+
const labels = new Set();
162+
const scripts = new Set();
163+
const normalizedText = normalizeName(text);
164+
if (!normalizedText) return { labels, scripts };
165+
166+
const paddedText = ` ${normalizedText} `;
167+
for (const [alias, label] of gameAliasToLabel.entries()) {
168+
if (alias.length < 3) continue;
169+
if (!paddedText.includes(` ${alias} `)) continue;
170+
labels.add(label);
171+
const mappedScript = gameAliasToScript.get(alias);
172+
if (mappedScript) scripts.add(mappedScript);
173+
}
174+
175+
return { labels, scripts };
176+
}
177+
160178
function parseServerlistCsv(csvText) {
161179
const rows = [];
162180
const lines = (csvText || '').split(/\r?\n/);
@@ -418,6 +436,13 @@ jobs:
418436
if (mappedScript) desiredServerScripts.add(mappedScript);
419437
}
420438
439+
// Legacy issues often have no form section; fall back to deterministic text matching.
440+
if (desiredGames.size === 0) {
441+
const fromText = findGamesFromText(`${title}\n${body}`, gameAliasToLabel, gameAliasToScript);
442+
for (const label of fromText.labels) desiredGames.add(label);
443+
for (const scriptName of fromText.scripts) desiredServerScripts.add(scriptName);
444+
}
445+
421446
// AI advisory is only needed on issue opened/edited.
422447
let triage = {};
423448
let ranAi = false;
@@ -900,6 +925,24 @@ jobs:
900925
.filter(Boolean);
901926
}
902927
928+
function findGamesFromText(text, gameAliasToLabel, gameAliasToScript) {
929+
const labels = new Set();
930+
const scripts = new Set();
931+
const normalizedText = normalizeName(text);
932+
if (!normalizedText) return { labels, scripts };
933+
934+
const paddedText = ` ${normalizedText} `;
935+
for (const [alias, label] of gameAliasToLabel.entries()) {
936+
if (alias.length < 3) continue;
937+
if (!paddedText.includes(` ${alias} `)) continue;
938+
labels.add(label);
939+
const mappedScript = gameAliasToScript.get(alias);
940+
if (mappedScript) scripts.add(mappedScript);
941+
}
942+
943+
return { labels, scripts };
944+
}
945+
903946
function parseServerlistCsv(csvText) {
904947
const rows = [];
905948
const lines = (csvText || '').split(/\r?\n/);
@@ -1203,6 +1246,14 @@ jobs:
12031246
const mappedScript = gameAliasToScript.get(normalizedCandidate);
12041247
if (mappedScript) desiredServerScripts.add(mappedScript);
12051248
}
1249+
1250+
// Legacy issues often have no form section; fall back to deterministic text matching.
1251+
if (desiredGames.size === 0) {
1252+
const fromText = findGamesFromText(`${title}\n${body}`, gameAliasToLabel, gameAliasToScript);
1253+
for (const label of fromText.labels) desiredGames.add(label);
1254+
for (const scriptName of fromText.scripts) desiredServerScripts.add(scriptName);
1255+
}
1256+
12061257
for (const gameLabel of desiredGames) {
12071258
const mappedScript = gameAliasToScript.get(normalizeName(gameLabel.slice(6)));
12081259
if (mappedScript) desiredServerScripts.add(mappedScript);

0 commit comments

Comments
 (0)