The skill system had a split brain

For a few months our skill system had two brains. `ACharacterEntity` kept its own map of skills and its own activation path. `UGenericSkillHandlerComponent` also existed, was more featureful (cooldowns, slots, delegates) and was largely bypassed.

Nobody decided this. It is what happens when a component gets written to do a job properly, the character already half-did that job, and deleting the half-version is never the most urgent thing in the sprint.

What two sources of truth actually cost

The symptom was not a crash. It was UI that bound to whichever path the last person had touched. A skill added through the component would not appear on a HUD bound to character delegates, and the fix looked like a UI bug, so it got fixed in the UI, twice, in different places.

The second cost was reach. `UCharacterSkillBase` held a hard `ACharacterEntity*`. That single pointer type meant a skill could never belong to a turret, a vehicle, or a destructible. And we wanted a turret. The class name said Character and the architecture had quietly agreed with it.

Making one of them authoritative

The fix is unglamorous: pick the better implementation, make it the only implementation, and reduce the other to forwarding. The component already had the features, so the component won and the entity became an adapter.

The interesting work was not that function. It was the order of operations: audit the component for anything the character had that it lacked, repoint the character's calls, and only then delete the duplicated map. Delete first and you spend a day rediscovering which delegate a widget three folders away depended on.

Every existing UI binding pointed at character events and had to be repointed at the component. That was the real bill for the refactor, and it is the bill you always pay when two systems have been publicly observable for months: the coupling is not in the systems, it is in everything watching them.

The honest cost of composition

This is the trade people skip when they recommend composition, so: you can no longer read one class and know what an actor does. `ACharacterEntity` now tells you almost nothing. To answer 'what happens when this thing is hit' you open the combat component, the stats component and the status effect component.

On a nine-person team that trade is worth taking, because the alternative is a hierarchy where adding a behaviour means understanding four parent classes and nobody has time for that in week seven. On a two-person project I might not make the same call. Composition is not free; it moves the cost from 'hard to extend' to 'hard to read in one place'.

What is still not done

Costs and requirements are still checked per-skill in code. The design I wrote down was for gameplay tags to carry both: a skill declares the tags that block it, the handler checks the owner's tag container, and a designer can gate a skill on 'in air' or 'stunned' without a programmer. That pass has not happened.

The class is also still called `UCharacterSkillBase` when it no longer needs a character. Renaming it is a five-minute job I have not done, and I am leaving it here as an accurate description of the codebase rather than the version of it that sounds finished.