```python
"""Select fictional campaign proposals by descending priority."""

import re
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP


_DECIMAL_PATTERN = re.compile(
    r"[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?"
)


def _cost_in_cents(row):
    """Validate an eligible row's cost and return integer cents."""
    if "price" in row:
        price = row["price"]
        if not isinstance(price, str):
            raise ValueError("price must be a finite nonnegative decimal string")

        text = price.strip()
        if _DECIMAL_PATTERN.fullmatch(text) is None:
            raise ValueError("price must be a finite nonnegative decimal string")

        try:
            dollars = Decimal(text)
        except (InvalidOperation, ValueError) as exc:
            raise ValueError(
                "price must be a finite nonnegative decimal string"
            ) from exc

        if not dollars.is_finite() or dollars < 0:
            raise ValueError("price must be a finite nonnegative decimal string")

        if dollars.is_zero():
            return 0

        # Shift the exponent exactly, independent of decimal context precision.
        sign, digits, exponent = dollars.as_tuple()
        try:
            cents = Decimal((sign, digits, exponent + 2))
            return int(cents.to_integral_value(rounding=ROUND_HALF_UP))
        except (InvalidOperation, ValueError, OverflowError) as exc:
            raise ValueError("price cannot be converted to integer cents") from exc

    if "cost_cents" not in row:
        raise ValueError("legacy rows must have cost_cents")

    cost_cents = row["cost_cents"]
    if (
        isinstance(cost_cents, bool)
        or not isinstance(cost_cents, int)
        or cost_cents < 0
    ):
        raise ValueError("cost_cents must be a nonnegative integer")

    return cost_cents


def plan(rows, budget_cents, excluded_channels=()):
    """Deduplicate, filter, validate, then select in stable priority order."""
    if (
        isinstance(budget_cents, bool)
        or not isinstance(budget_cents, int)
        or budget_cents < 0
    ):
        raise ValueError("budget_cents must be a nonnegative integer")

    normalized_exclusions = {
        channel.strip().casefold() for channel in excluded_channels
    }
    seen_ids = set()
    proposals = []

    for row in rows:
        row_id = row["id"]
        if row_id in seen_ids:
            continue
        seen_ids.add(row_id)

        if row.get("archived", False):
            continue

        channel = row.get("channel", "").strip().casefold()
        if channel in normalized_exclusions:
            continue

        cost_cents = _cost_in_cents(row)
        proposals.append((row_id, row.get("priority", 0), cost_cents))

    proposals.sort(key=lambda proposal: proposal[1], reverse=True)

    selected_ids = []
    skipped_ids = []
    remaining_cents = budget_cents

    for row_id, priority, cost_cents in proposals:
        if cost_cents <= remaining_cents:
            selected_ids.append(row_id)
            remaining_cents -= cost_cents
        else:
            skipped_ids.append(row_id)

    return {
        "selected_ids": selected_ids,
        "spent_cents": budget_cents - remaining_cents,
        "remaining_cents": remaining_cents,
        "skipped_ids": skipped_ids,
    }
```