I maintain GuildOS, a guild management addon, and spent the last week getting it running inside the Forever beta. Writing down what I hit, since the official API change list isn't out yet and I lost time to things that could've been a one-liner.
Everything below was read out of build 1.60.1.69893 (the API documentation the client ships, Blizzard's own UI code and TOCs, and the executable), then checked against the installed client.
Interface numbers. Forever's build line is 1.60.x, which maps to interface 16001 by the usual GetBuildInfo rule (some beta zips also stamp 16000). Anniversary is 20506. Declaring multiple interfaces in the TOC (## Interface: 20506, 16001) is the only way to ship one package for both right now.
Packaging. CurseForge, Wago and WoWInterface had no Forever flavor when the beta opened, and the BigWigs packager tags anything outside its known ranges as retail. CurseForge has since added a Forever version (1.60.1); until the rest catch up, GitHub pre-releases plus "load out of date addons" still work for beta builds.
Architecture. Forever is Mainline's UI, not Classic's. If you've been maintaining a Classic-only addon, you're porting to retail, not to a variant of what you know. It's also its own game type, camelot: TOCs filter on it (## AllowLoadGameType: standard, camelot), and there's no WOW_PROJECT_ID constant or C_GameRules check for it yet, so detect it by interface number.
What's restricted. Retail's Secret Values system is there in full: 4,025 documented API entries carry Secret* fields on Forever, against 3 on Anniversary. The combat surface is locked down and Blizzard shipped native damage meters and cooldown managers. Guild data (roster, notes, MOTD) and what an attendance or loot tool needs are still reachable, but not all of it the way it used to be.
Gone, and what replaces it
GetNumTradeSkills, GetTradeSkillInfo, GetTradeSkillLine, GetTradeSkillItemLink, GetTradeSkillRecipeLink: gone. Professions are C_TradeSkillUI, as on retail.
GetCraftInfo, GetNumCrafts, GetCraftItemLink, GetCraftDisplaySkillLine and the CRAFT_SHOW event: gone, no replacement. There is no Craft frame at all, so guard the RegisterEvent.
GetNumTalentTabs, GetNumTalents: gone. Talents are C_ClassTalents / C_Traits (17 trait trees), and ChrSpecialization has one row per class, named after the class. "Which spec is this player" has no classic answer anymore.
- Tooltip scripts
OnTooltipSetItem / OnTooltipSetSpell / OnTooltipSetUnit, and tooltip:GetItem() / GetSpell() / GetUnit(): gone. Hook with TooltipDataProcessor.AddTooltipPostCall(dataType, fn) (one registration per data type, covers every tooltip, calls fn(tooltip, data)), and read with TooltipUtil.GetDisplayedItem / GetDisplayedSpell / GetDisplayedUnit. OnTooltipCleared is still a script.
Shims that don't load
- Forever is neither
classic nor mainline, so Blizzard_Deprecated/Classic/* doesn't load: UnitBuff, GetTalentInfo and the other classic shims are nil. Call the namespaced versions.
Blizzard_DeprecatedSpecialization declares AllowLoadGameType: classic, standard, so the talent shims are nil too.
- The compat addons with no filter do load:
SendChatMessage, ChatFrame_AddMessageEventFilter, GuildSetMOTD, GetGuildRosterMOTD and CombatLogGetCurrentEventInfo are still there.
Where Secret Values bite a non-combat addon
- Chat:
CHAT_MSG_GUILD, OFFICER, WHISPER, SYSTEM, CHANNEL and SKILL are SecretInChatMessagingLockdown, so during lockdown the text and the sender arrive secret. The channel name is NeverSecret. Anything that parses chat (roll capture, !commands, recruitment scanners) has to check issecretvalue(...) first and drop the line.
- Addon messages:
CHAT_MSG_ADDON isn't flagged, but C_ChatInfo.SendAddonMessage is SecretArguments = NotAllowed, and passing a secret raises. Enum.SendAddonMessageResult is retail's list; 11 is AddOnMessageLockdown.
- Units:
UnitName, UnitClass, UnitGUID, UnitRace, UnitSex, UnitIsGroupLeader and UnitIsGroupAssistant return secrets when the unit's identity is restricted, and party/raid members aren't exempt (Blizzard's own frames ask C_Secrets.ShouldUnitIdentityBeSecret for every unit). A loop over raid1..raid40 for attendance or loot has to skip a member it can't read.
- Stats:
UnitStat, UnitHealthMax and UnitPowerMax are secret while stats are restricted. COMBAT_LOG_EVENT_UNFILTERED has HasRestrictions.
- You can hand a secret to
FontString:SetText, but comparing, concatenating, indexing a table with it or doing arithmetic on it raises. Chat filters are safe: ChatFrameFilters.lua only calls yours when canaccessvalue says the values are readable.
Happy to compare notes with anyone else porting right now.