export interface PartyCastPresentationEvent { readonly actorGroup: string; readonly sourceActorId: string; readonly abilityId?: string; readonly phase: string; readonly instantCast?: boolean; } /** Tracks one completed companion cast across multi-pulse channel releases. */ export class PartyCastTelemetry { private readonly startedCasts = new Map(); record(event: PartyCastPresentationEvent): boolean { if (event.actorGroup !== "party" || !event.abilityId || event.abilityId === "party-auto-attack") return false; const key = `${event.sourceActorId}\u0000${event.abilityId}`; if (event.phase === "cast-start") { this.startedCasts.set(key, false); return false; } if (event.phase === "cast-cancel") { this.startedCasts.delete(key); return false; } if (event.phase !== "release") return false; if (event.instantCast) return true; if (!this.startedCasts.has(key) || this.startedCasts.get(key)) return false; this.startedCasts.set(key, true); return true; } }