# Dalamud API 15 / v15.0.0.0 to v15.0.0.3 Update Report

Checked: `2026-05-04`  
Audience: Dalamud plugin developers migrating to API 15 or validating Patch 7.5 compatibility.

## Sources

- Official v15 page: `https://dalamud.dev/versions/v15/`
- Official API reference: `https://dalamud.dev/api/`
- Major v15 code diff named by the official page: `https://github.com/goatcorp/Dalamud/compare/14.0.5.2...15.0.0.1`
- Dalamud `15.0.0.1 -> 15.0.0.2`: `https://github.com/goatcorp/Dalamud/compare/15.0.0.1...15.0.0.2`
- Dalamud `15.0.0.2 -> 15.0.0.3`: `https://github.com/goatcorp/Dalamud/compare/15.0.0.2...15.0.0.3`
- ClientStructs `e2cebc4 -> bd1f11f`: `https://github.com/aers/FFXIVClientStructs/compare/e2cebc4f4526a5e87cc13eef97af8e86f79b42cf...bd1f11f22ed931162d98ea8b5355f152264d6365`
- ClientStructs `bd1f11f -> 93f4966`: `https://github.com/aers/FFXIVClientStructs/compare/bd1f11f22ed931162d98ea8b5355f152264d6365...93f4966c6916d0a2f2e8d89e542767d5aebc0026`
- ClientStructs 7.5 breaking notes: `https://ffxiv.wildwolf.dev/docs/breaking/7.5.html`

## Important Version Note

As of this check, `goatcorp/Dalamud` does not expose a public Git tag named `15.0.0.0`. The official API/package baseline is `Dalamud.NET.Sdk/15.0.0` and `DalamudPackager/15.0.0`, while the public Dalamud runtime tags start at `15.0.0.1`.

For a practical "v15.0.0.0 to v15.0.0.3" migration report, read this as:

- API/package baseline: `Dalamud.NET.Sdk/15.0.0`
- major API 15 runtime baseline: `15.0.0.1`
- hotfix endpoint covered here: `15.0.0.3`

## Executive Summary

API 15 is a real migration boundary, not just a version bump. The biggest breakpoints are `.NET 10`, `Dalamud.NET.Sdk/15.0.0`, new chat message interfaces, `IClientState` removals, `XivChatType` relation cleanup, ImRaii ref-struct changes, manifest packaging behavior, and FFXIVClientStructs enum/native layout movement.

The `15.0.0.2` and `15.0.0.3` tags are mostly stabilization hotfixes after the initial API 15 release. They matter because they fix hook verification behavior, `CheckMessageHandled` forwarding, duty/unlock hooks, viewport/window behavior, plugin installer duplicate entries, and the paired ClientStructs layouts used by queue, party finder, UI, input, and addon tooling.

NuGet did not move past `Dalamud.NET.Sdk/15.0.0` or `DalamudPackager/15.0.0` during this review. Plugin projects should still target:

```xml
<Project Sdk="Dalamud.NET.Sdk/15.0.0">
```

## Release Timeline

| Stage | What it represents | Commit / version | Main impact |
| --- | --- | --- | --- |
| Official API 15 package baseline | Public SDK and packager | `Dalamud.NET.Sdk/15.0.0`, `DalamudPackager/15.0.0` | Plugin project migration target. |
| Major API 15 runtime tag | First public v15 runtime tag in this line | `15.0.0.1` / `4f2c9024` | Contains the major API 15 breaking changes. |
| Hotfix runtime tag | First stabilization tag after `.1` | `15.0.0.2` / `a428fa9` | Hook verifier, UnlockState, chat event forwarding, submodule updates. |
| Hotfix runtime tag | Second stabilization tag after `.1` | `15.0.0.3` / `d694ab2` | Window/viewport behavior, GlobalScale safety, plugin installer duplicate fix, Lumina 7.4.0, ClientStructs update. |

## Major API 15 Changes From The Official v15 Page

### New async plugin lifecycle

API 15 adds `IAsyncDalamudPlugin`. Use it when plugin load or disposal genuinely needs asynchronous work. The plugin is not considered loaded until async load completes successfully. Work that must run on the game/main thread should be routed through `IFramework.Run()`.

Old pattern:

```csharp
public sealed class Plugin : IDalamudPlugin
{
    public Plugin()
    {
        Task.Run(InitializeAsync).GetAwaiter().GetResult();
    }
}
```

New pattern:

```csharp
public sealed class Plugin : IAsyncDalamudPlugin
{
    public async Task LoadAsync(CancellationToken token)
    {
        await LoadDataAsync(token);
        await Plugin.Framework.Run(() => InitializeMainThreadState(), token);
    }

    public async ValueTask DisposeAsync()
    {
        await DisposeAsyncCore();
    }
}
```

Use `IAsyncDalamudPlugin` deliberately. A normal `IDalamudPlugin` remains appropriate for simple plugins.

### Chat API 15

Chat events now pass message objects/interfaces instead of the old multi-parameter/ref-style payloads. Mutable messages expose setters, and handleable messages expose `PreventOriginal()`.

Old pattern:

```csharp
chatGui.ChatMessage += (type, timestamp, ref sender, ref message, ref handled) =>
{
    handled = true;
};
```

New pattern:

```csharp
chatGui.CheckMessageHandled += message =>
{
    if (message.LogKind == XivChatType.ErrorMessage)
        message.PreventOriginal();
};
```

Do not use invalid `XivChatType` values above `110` for relation data anymore. Use the source/target relation fields on the message instead, and consider `LogMessage` for stable system-message handling.

### `IClientState` removals

`IClientState.LocalPlayer` and `IClientState.LocalContentId` are removed from the API 15 migration path.

Old pattern:

```csharp
var player = clientState.LocalPlayer;
var contentId = clientState.LocalContentId;
```

New pattern:

```csharp
var player = objectTable.LocalPlayer;
var contentId = playerState.ContentId;
```

Audit any database IDs, JSON payloads, IPC DTOs, and UI formatting that assumed content IDs were signed integers.

### Manifest packaging is stricter

The plugin JSON inside the zip is now authoritative at install time. Do not rely on a repository manifest overwriting the packaged manifest.

Before publishing, inspect the zip and verify:

- exactly one `InternalName.json`
- correct `InternalName`
- correct `AssemblyVersion`
- `DalamudApiLevel` set to `15`
- icon/assets included
- no stale debug or local-only files

### ImRaii changes

ImRaii disposable helpers moved away from boxed end-object patterns and toward ref-struct scoped disposables. Most code using `var` and normal `using` scope should migrate cleanly, but old explicit `IEndObject` usage needs to be replaced.

Old pattern:

```csharp
IEndObject disabled = ImRaii.Disabled();
disabled.Dispose();
```

New pattern:

```csharp
using var disabled = ImRaii.Disabled();
```

### Enum and native type resync

Many Dalamud enums now mirror FFXIVClientStructs. This is more accurate, but it means stale enum names can fail to compile or silently map to different values if a plugin used hardcoded numeric assumptions.

Common migration examples:

| Old pattern | New/API 15 direction |
| --- | --- |
| `HoverActionKind` | `DetailKind` |
| `ValueType` for `AtkValue.Type` | `AtkValueType` |
| `ObjectKind.Player` assumptions | verify current `ObjectKind` names from ClientStructs |
| `IPartyMember.ContentId` as `long`/`int` | `ulong` |
| `ICharacter.Customize` as `byte[]` | `Span<byte>` |

## Dalamud `15.0.0.1 -> 15.0.0.2`

This hotfix range has 16 commits and 10 changed files.

### Hook verifier

Hook verification now uses already-resolved addresses from ClientStructs instead of scanning the same signatures again. It also builds verification entries in parallel, includes canonical signatures in mismatch errors, and adds a self-test step.

Why this matters:

- bad hook delegates are more likely to fail early with a useful error
- plugins using unsafe hooks should recheck delegate signatures against ClientStructs
- mismatches that previously slipped by may now be visible

Old risk:

```csharp
private delegate void SomeHook(nint thisPtr, byte flag);
```

Safer direction:

```csharp
private delegate void SomeHook(nint thisPtr, bool flag);
```

Do not guess the parameter type from old notes. Use the current ClientStructs delegate when one exists.

### UnlockState hook replacement

`UnlockState` stopped using raw scanned signatures for ornament and glasses-style unlock hooks and switched to ClientStructs member function pointers/delegates. The boolean unlock parameter is now treated as `bool`, not a raw byte.

Plugin impact:

- this mostly stabilizes Dalamud internals
- plugins with similar hooks should prefer ClientStructs delegates/member pointers over copied signatures
- byte-vs-bool delegate mismatches should be reviewed

### `CheckMessageHandled` forwarding fix

Plugin-scoped `IChatGui.CheckMessageHandled` is now actually subscribed to the underlying service event.

What was broken:

- plugins subscribing through their injected `IChatGui` could miss `CheckMessageHandled`
- chat suppression/fixup logic written for API 15 may not have fired correctly before this hotfix

What to test:

- any plugin using `CheckMessageHandled`
- any plugin using `PreventOriginal()` to suppress chat output
- any plugin with fallback or workaround code for missed API 15 chat events

## Dalamud `15.0.0.2 -> 15.0.0.3`

This hotfix range has 13 commits and 11 changed files.

### Window and viewport handling

`WindowHost` and Win32 viewport handling changed around clickthrough, z-ordering, error style, title-bar buttons, blur/alpha persistence, and non-main viewport input flags.

What was fixed or changed:

- platform viewport windows are raised in z-order on click without activating the window
- clickthrough title-bar controls handle hover/click more explicitly
- title-bar button sorting and drawing were reworked
- error windows use a safer fallback style and avoid running normal pre/post draw paths while in error state
- blur factor override is persisted in the window preset model

Plugin impact:

- custom `TitleBarButton` code should be smoke-tested
- clickthrough/pinned/non-main-viewport windows should be manually tested
- code that mutates `Window.TitleBarButtons` during draw should be watched for order/interaction differences

### `ImGuiHelpers.GlobalScale`

`GlobalScale` is now safe to call before ImGui initialization. `GlobalScaleSafe` remains, but is obsolete and should be replaced.

Old pattern:

```csharp
var scale = ImGuiHelpers.GlobalScaleSafe;
```

New pattern:

```csharp
var scale = ImGuiHelpers.GlobalScale;
```

This is not usually an immediate compile break, but it is a cleanup item before API 16 because the obsolete property is marked for removal later.

### Plugin installer duplicate-entry fix

The plugin installer changed how it associates installed plugins with available manifests. It now accounts for third-party source repo URLs instead of matching only the old manifest `RepoUrl` shape.

Plugin impact:

- custom repository maintainers should retest installed/available plugin matching
- duplicate plugin entries in the installer should be reduced
- manifests still need accurate `InternalName`, `AssemblyVersion`, and source metadata

### Dependency movement

Dalamud runtime moved:

- internal runtime version: `15.0.0.1 -> 15.0.0.3`
- `Lumina`: `7.2.0 -> 7.4.0`
- `lib/FFXIVClientStructs`: `e2cebc4 -> 93f4966`

The public plugin SDK and packager package versions did not move past `15.0.0`.

## FFXIVClientStructs Changes Paired With These Hotfixes

The supplied ClientStructs ranges total 48 commits and 41 changed files.

### High-risk native changes

| Area | Change | Plugin risk |
| --- | --- | --- |
| UI readiness | `UIModuleInterface.IsUIReady` added | Prefer this over fragile readiness guesses when available. |
| Framework exit | `Framework.ExitFromWindow` added | Useful for launcher/window-exit paths; direct callers should verify semantics. |
| Item finder | `IsCabinetCached` replaced by `CabinetState`; old bool is obsolete/error | Direct users of `IsCabinetCached` will fail to compile. |
| Addon collision | `AtkUnitManager.GetAddonCollision` and `AddonCollision` added | Useful for addon inspection and hit testing. |
| Queue state | queue packet structs and `ContentsFinderQueueInfo` fields added/corrected | Duty finder, queue overlays, instant queue actions, and raw queue hooks need tests. |
| Party finder | `AddonLookingForGroup`, `AddonLookingForGroupBase`, `AddonLookingForGroupCondition`, `AgentRaidFinder` added | Party Finder automation/inspection can use typed structs instead of raw offsets. |
| Input IDs | `XBM_BOOK` inserted and later input IDs shifted | Hardcoded numeric `InputId` values may be wrong. |
| ULD duplication | `AtkUldManager` duplicate-node helpers added | Useful for advanced UI/addon tooling. |
| Model/render | `CharacterBase`, `ModelRenderer`, and material fields changed | Appearance/model plugins should retest direct native access. |

### `ItemFinderModule` old/new example

Old pattern:

```csharp
if (itemFinder->IsCabinetCached)
    UseCabinetData();
```

New pattern:

```csharp
if (itemFinder->CabinetState != 0)
    UseCabinetData();
```

Check the current `Cabinet.CabinetState` meaning before treating every non-zero value as "fully loaded".

### `ContentsFinderQueueInfo` old/new example

Old assumptions:

```csharp
var waitKnown = queueInfo->InfoState.AverageWaitTime;
var inProgress = queueInfo->PoppedContentIsInProgress; // may not have existed in older local structs
```

New direction:

```csharp
var averageWaitMinutes = queueInfo->InfoState.AverageWaitTime;
var inProgress = queueInfo->PoppedContentIsInProgress;
var lootRule = queueInfo->PoppedContentLootRule;
var limitedLeveling = queueInfo->PoppedContentIsLimitedLeveling;
```

The important point is that raw queue offsets and old boolean interpretations need retesting.

### `InputId` shift

`XBM_BOOK` was inserted at `524`, shifting several later IDs by one.

Old hardcoded value risk:

```csharp
const int PadMap = 524;
```

Safer direction:

```csharp
var padMap = InputId.PAD_MAP;
```

If a plugin stores numeric input IDs in config, it needs a migration or validation pass.

## Known Issues And Things That Broke

### Known official issue

Plugins that fail to load during update can show as not installed. Check logs before assuming the plugin was removed.

### Practical break list

| Break / risk | Who is affected | Fix |
| --- | --- | --- |
| Old SDK/package header | Any plugin still on API 14 SDK | Use `Dalamud.NET.Sdk/15.0.0`. |
| Stale zip manifest | Any plugin release pipeline | Inspect packaged `InternalName.json`; do not rely on repo manifest replacement. |
| Removed `IClientState.LocalPlayer` / `LocalContentId` | Plugins reading local player/content ID from client state | Use `IObjectTable.LocalPlayer` and `IPlayerState.ContentId`. |
| Old chat delegate signatures | Plugins intercepting/mutating chat | Use `IChatMessage`, `IMutableChatMessage`, `IHandleableChatMessage`, `ILogMessage`. |
| Out-of-range `XivChatType` relation hacks | Chat routing/filter plugins | Use `SourceKind` and `TargetKind`. |
| `CheckMessageHandled` pre-hotfix behavior | Plugins using plugin-scoped `IChatGui.CheckMessageHandled` | Retest on `15.0.0.2+`; remove workarounds if needed. |
| `GlobalScaleSafe` | UI plugins | Replace with `GlobalScale`; old property is obsolete. |
| `ItemFinderModule.IsCabinetCached` | Inventory/search plugins using ClientStructs directly | Use `CabinetState`. |
| Hardcoded `InputId` values | Input/bind plugins | Use enum names and migrate stored numeric values. |
| Raw queue offsets | Duty finder/queue plugins | Retest against new `ContentsFinderQueueInfo` and queue packet structs. |
| Bad hook delegate types | Unsafe hook plugins | Prefer ClientStructs delegates/member function pointers; retest with hook verifier. |

## New Features Worth Using

- `IAsyncDalamudPlugin` for async load/dispose.
- `IFramework.Run()` for main-thread work from async paths.
- `IChatGui` message interfaces and `PreventOriginal()`.
- `LogMessage` for stable system-message handling.
- `IAddonLifecycle` and `IAgentLifecycle` `PreventOriginal()` for carefully proven suppression.
- `IGameGui.OpenMapWithMapLink(uint territory, uint map, Vector3 worldPos)`.
- UiDebug `StringMappedCustomNodes` labels for plugin-attached custom nodes.
- `UIModuleInterface.IsUIReady`.
- `AtkUnitManager.GetAddonCollision`.
- Typed LookingForGroup/RaidFinder addon and agent structs.
- `ScheduleManagement.IsCutScenePlaying()` on current ClientStructs main after the `15.0.0.3` pair.

## Recommended Migration Order

1. Update project SDK to `Dalamud.NET.Sdk/15.0.0`.
2. Set manifest `DalamudApiLevel` to `15`.
3. Restore packages and update lockfiles.
4. Fix compile errors for removed `IClientState` members, enum renames, chat signatures, `AtkValueType`, and content ID type changes.
5. Replace `GlobalScaleSafe` with `GlobalScale`.
6. Replace `ItemFinderModule.IsCabinetCached` with `CabinetState` if using ClientStructs directly.
7. Audit hardcoded input IDs and queue offsets.
8. Verify packaged manifest contents before publishing.
9. Runtime-test chat suppression, addon lifecycle, unsafe hooks, queue/duty code, and custom UI windows.

## Runtime Smoke Test Checklist

- Plugin loads cleanly on API 15.
- `/xllog` has no load, signature, hook verifier, or manifest errors.
- Main/config windows open.
- Custom title-bar buttons still work.
- Clickthrough and pinned windows behave correctly.
- Chat handlers receive expected events.
- `PreventOriginal()` suppresses only the intended messages/events.
- Addon lifecycle listeners register and unregister cleanly.
- Unsafe hooks enable, fire, disable, and dispose cleanly.
- Duty/queue surfaces work after the ClientStructs queue changes.
- Release zip installs from a custom repo and shows API 15.

## Post-15.0.0.3 Watch Items

After `15.0.0.3`, Dalamud `master` moved again. These commits were not part of the `15.0.0.3` tag, but they are worth watching:

- `IClientState.IsClientIdle()` now also checks the game input timer and requires 30 seconds of idle input time when that module is active.
- `UiBuilder` plugin draw exceptions now keep callbacks and show a richer error window with retry/reload behavior.
- dev plugin validation flags `InternalName == "SamplePlugin"` as fatal.
- boot plugin-load cancellation logging changed.

ClientStructs `main` also moved after the `93f4966` paired commit:

- `SoundManager` bus arrays changed shape.
- `ScheduleManagement.IsCutScenePlaying()` was added.
- `VfxContainer.LoadCharacterSound` gained clarified parameter names and future type TODOs.

Treat these as watch items unless you are building directly against the latest source beyond the `15.0.0.3` tag.

## Changed Files Appendix

### Dalamud `15.0.0.1 -> 15.0.0.3`

The hotfix range changed these 19 Dalamud paths:

- `Dalamud/Dalamud.cs`
- `Dalamud/Dalamud.csproj`
- `Dalamud/Game/Gui/ChatGui.cs`
- `Dalamud/Game/UnlockState/UnlockState.cs`
- `Dalamud/Hooking/Internal/Verification/HookVerificationException.cs`
- `Dalamud/Hooking/Internal/Verification/HookVerifier.cs`
- `Dalamud/Interface/ImGuiBackend/InputHandler/Win32InputHandler.cs`
- `Dalamud/Interface/Internal/InterfaceManager.cs`
- `Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs`
- `Dalamud/Interface/Internal/Windows/SelfTest/Steps/DalamudSelfTest.cs`
- `Dalamud/Interface/Internal/Windows/SelfTest/Steps/HookVerifierSelfTestStep.cs`
- `Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs`
- `Dalamud/Interface/Utility/ImGuiHelpers.cs`
- `Dalamud/Interface/Windowing/WindowHost.cs`
- `Dalamud/Interface/Windowing/WindowSizeConstraints.cs`
- `Dalamud/Plugin/Internal/Types/Manifest/ILocalPluginManifest.cs`
- `Directory.Packages.props`
- `lib/FFXIVClientStructs`
- `lib/Lumina.Excel`

### ClientStructs `e2cebc4 -> 93f4966`

The paired ClientStructs range changed these 41 paths:

- `FFXIVClientStructs/FFXIV/Application/Network/LobbyClient/LobbyRequestCallback.cs`
- `FFXIVClientStructs/FFXIV/Client/Enums/TerritoryIntendedUse.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Control/Control.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/CraftEventHandler.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/CustomTalkEventHandler.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/Director.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/EventHandler.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/FishingEventHandler.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/LuaEventHandler.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/ShopEventHandler.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Fate/FateDirector.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/InstanceContent/ContentDirector.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/InstanceContent/InstanceContentDirector.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/InstanceContent/PublicContentDirector.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/InstanceContent/PublicContentOccultCrescent.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Network/QueuePackets.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/UI/ContentsFinder.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/UI/UIState.cs`
- `FFXIVClientStructs/FFXIV/Client/Graphics/Render/ModelRenderer.cs`
- `FFXIVClientStructs/FFXIV/Client/Graphics/Scene/CharacterBase.cs`
- `FFXIVClientStructs/FFXIV/Client/Network/PacketDispatcher.cs`
- `FFXIVClientStructs/FFXIV/Client/System/Framework/Framework.cs`
- `FFXIVClientStructs/FFXIV/Client/System/Input/InputData.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/AddonCharaSelectWorldServer.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/AddonLookingForGroup.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/AddonLookingForGroupBase.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/AddonLookingForGroupCondition.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/AddonRaidFinder.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentInterface.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentLobby.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentLookingForGroup.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentRaidFinder.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/Agent/LobbyUIClient.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/Misc/ItemFinderModule.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/UIModuleInterface.cs`
- `FFXIVClientStructs/FFXIV/Component/Excel/RingBufferExcelPageRowResolver.cs`
- `FFXIVClientStructs/FFXIV/Component/GUI/AtkModuleInterface.cs`
- `FFXIVClientStructs/FFXIV/Component/GUI/AtkUldManager.cs`
- `FFXIVClientStructs/FFXIV/Component/GUI/AtkUnitManager.cs`
- `ida/data.yml`
- `ida/ffxiv_structs.yml`

### Official Major API 15 Diff

The official page's major code diff, `14.0.5.2 -> 15.0.0.1`, contains 222 commits and 204 changed files. The highest-impact file groups are:

- chat: `ChatGui`, `ChatMessage`, `IChatGui`, `XivChatType`, `XivChatTypeExtensions`
- plugin lifecycle: `IAsyncDalamudPlugin`, plugin interface, plugin manager and local plugin types
- client/duty state: `ClientState`, `ZoneInitEventArgs`, `DutyState`, `DutyStateEventArgs`
- addon/agent lifecycle: `AddonLifecycle`, `AgentLifecycle`, `PreventOriginal` handling
- native enum resync: object kind, inventory type, party finder flags, player attributes, `AtkValueType`
- ImRaii: ref-struct disposable rewrite and new scoped helpers
- windowing: `Window`, `IWindow`, `WindowHost`, `WindowSystem`, title-bar buttons
- hook/signature safety: `Hook`, `HookManager`, `HookVerifier`, `SigScanner`, base address resolver
- manifest/install behavior: local/remote manifest types and plugin package handling
- ClientStructs/Lumina submodules

## Bottom Line

For plugin authors, the mandatory target is still `Dalamud.NET.Sdk/15.0.0`, but the runtime reality is now at least `15.0.0.3`. The hotfixes are not mostly cosmetic: they affect hook verification, chat event forwarding, viewport/window behavior, plugin installer matching, and native ClientStructs layouts. A clean compile is necessary, but it is not enough; API 15 requires in-game smoke testing for chat, hooks, addon/native UI, queue/duty, and release packaging.
