discord:setup: der zweite Lauf schreibt wirklich nichts mehr

Der Bauplan verspricht, dass ein zweiter Lauf nichts aendert. Zwei Schritte
haben das gebrochen, weil sie ohne Vergleich geschrieben haben: die
Servereinstellungen und die Rangfolge der Rollen.

Aufgefallen beim Einrichten des Technik-Webhooks - der Lauf meldete "GESETZT
abdulive_" und "GESETZT Rangfolge", obwohl die Vorschau zuvor "steht" gesagt
hatte. Vorschau und echter Lauf sagten also Verschiedenes.

Folgenlos war es nicht: jeder Lauf kostete zwei Aufrufe und hinterliess zwei
Eintraege im Audit-Log des Servers, einen davon eine Rollen-Umsortierung.

Jetzt wird beides vorher verglichen. ApiGuild traegt dafuer die vier Felder
aus GUILD_SETTINGS. Ein Test haelt es fest: nach einem Lauf darf der zweite
weder PATCH /guilds/{id} noch PATCH /guilds/{id}/roles schicken.

Am echten Server nachgeprueft - der dritte Lauf meldet keine Aenderung mehr.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZeasyAlexandClaude Opus 5 committed 2026-09-18 00:12:58 +02:00
1 parent c4dc6ee04f
commit e18336c57f
3 files changed
+64 -10

No files matched your search

+22 -3
View File
@@ -193,9 +193,11 @@ async function applyRoleOrder(
if (dry || wanted.length === 0) return;
let botTop: number;
let istPosition = new Map<string, number>();
try {
const member = await api.get<{ roles: string[] }>(`/guilds/${guild.id}/members/${botUserId}`);
const fresh = await api.get<ApiRole[]>(`/guilds/${guild.id}/roles`);
istPosition = new Map(fresh.map((r) => [r.id, r.position]));
botTop = fresh
.filter((r) => member.roles.includes(r.id))
.reduce((max, r) => Math.max(max, r.position), 0);
@@ -211,6 +213,15 @@ async function applyRoleOrder(
return;
}
// Stimmt die Rangfolge schon, nicht schreiben. Ein PATCH mit denselben
// Werten ist zwar folgenlos, kostet aber bei jedem Lauf einen Aufruf und
// einen Eintrag im Audit-Log - und laesst den Lauf so aussehen, als haette
// er etwas geaendert.
if (wanted.every((id, i) => istPosition.get(id) === fit.positions[i])) {
steps.push({ kind: 'Rollen', name: 'Rangfolge', change: 'unveraendert' });
return;
}
try {
await api.patch(`/guilds/${guild.id}/roles`,
wanted.map((id, i) => ({ id, position: fit.positions[i] })), 'Rangfolge aus dem Bauplan');
@@ -480,9 +491,17 @@ export async function applyPlan(
const me = await api.get<ApiUser>('/users/@me');
log.info(`Server "${guild.name}"${dry ? ' (Vorschau, es wird nichts geaendert)' : ''}`);
// 1. Servereinstellungen
if (!dry) await api.patch(`/guilds/${guild.id}`, GUILD_SETTINGS, 'Servereinstellungen aus dem Bauplan');
steps.push({ kind: 'Server', name: guild.name, change: dry ? 'unveraendert' : 'angepasst' });
// 1. Servereinstellungen. Vergleichen statt blind schreiben: sonst meldet
// jeder Lauf eine Aenderung, auch wenn es keine gab, und die Vorschau sagt
// etwas anderes als der echte Lauf.
const abweichend = (Object.entries(GUILD_SETTINGS) as Array<[keyof ApiGuild, number]>)
.some(([k, v]) => guild[k] !== v);
if (abweichend) {
if (!dry) await api.patch(`/guilds/${guild.id}`, GUILD_SETTINGS, 'Servereinstellungen aus dem Bauplan');
steps.push({ kind: 'Server', name: guild.name, change: dry ? 'erstellt' : 'angepasst' });
} else {
steps.push({ kind: 'Server', name: guild.name, change: 'unveraendert' });
}
// 2. Rollen
const roleIds = await applyRoles(api, guild, me.id, steps, dry);