> Should the shield be its own entity
> that tracks the location of the
> player? That might make it hard to
> implement the damage filtering. It
> also kinda blurs the lines between
> attached components and entities.

No

> Should the shield be a component that
> houses other components? I've never
> seen or heard of anything like this,
> but maybe it's common and I'm just not
> deep enough yet.

See it in a different perspective; adding a component adds other components as well, and upon removal, the additional components are gone too.

> Should the shield just be a set of
> components that get added to the
> player? Possibly with an extra
> component to manage the others, e.g.
> so they can all be removed as a group.
> (accidentally leave behind the damage
> reduction component, now that would be
> fun).

This could be a solution, it would promote reuse, however it is also more error prone (for the issue you mentioned, for instance). It's not necessarily bad. You might find out new spell combinations with trial and error :)
 
> Something else that's obvious to
> someone with more component
> experience?

I'm going to elaborate a bit.

I believe you noticed how some components should take priority no matter when they've been added to an entity (this would answer your other question as well).

I'm also going to assume we're using message-based communication (for the sake of discussion, it's just an abstraction over a method call for the moment).

Whenever a shield component is "installed", shield component message handlers are chained with a specific (higher) order.

 Handler Stage Handler Level Handler Priority
 In Pre System High
 Out Invariant High
 Post AboveNormal
 Normal
 BelowNormal
 Low
 System Low

 In - incoming messages
 Out - outgoing messages
 Index = ((int)Level | (int)Priority)

The "stats" component installs a "damage" message handler at the In/Invariant/Normal index.
 Every time a "damage" message is received, decrease the HP by its "value" amount.

Fairly standard behaviour (put in some natural damage resistance and / or racial traits, whatever).

The shield component installs a "damage" message handler at the In/Pre/High index.

 Every time a "damage" message is received, deplete the shield energy and substract
 the shield energy from the damage value, so that the damage down the message
 handler pipeline is reduced.

 damage -> stats
 stats
 stats.hp -= damage.value

 damage -> shield -> stats
 shield
 if(shield.energy) {
 remove_me();
 return;
 }
 damage.value -= shield.energyquantum
 shield.energy -= shield.energyquantum;

 stats
 stats.hp -= damage.value

You can see this is pretty flexible, albeit it would require careful planning when designing component interaction, as you're going to have to determine in which part of the message handling pipeline component message event handlers are installed.

Makes sense? Let me know if I can add more detail.