GuildJoinTask.Parse() reads data[guild_status].ToInt() directly; hardcoding 2 for the APPROVAL path was wrong. GuildOpResult gains nullable GuildStatus; JoinAsync sets 1 (APPLYING) for the pending-request path and 2 (JOINING) for instant joins. Controller reads r.GuildStatus. Two new tests assert the wire value per path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>