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

import re
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP


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


def _cost_in_cents(row):
    """Validate and convert an eligible row's cost to integer cents."""
    if "price" not in row:
        cost = row.get("cost_cents")
        if isinstance(cost, bool) or not isinstance(cost, int) or cost < 0:
            raise ValueError("cost_cents must be a nonnegative integer")
        return cost

    price = row["price"]
    if not isinstance(price, str):
        raise ValueError("price must be a finite nonnegative decimal string")

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

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

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

    if amount.is_zero():
        return 0

    # Shift dollars to cents exactly, without context-dependent multiplication.
    sign, digits, exponent = amount.as_tuple()
    cents = Decimal((sign, digits, exponent + 2))
    return int(cents.to_integral_value(rounding=ROUND_HALF_UP))


def plan(rows, budget_cents, excluded_channels=()):
    """Select affordable, eligible first occurrences in stable priority order."""
    if isinstance(budget_cents, bool) or not isinstance(budget_cents, int):
        raise ValueError("budget_cents must be a nonnegative integer")
    if 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()
    eligible = []

    for row in rows:
        proposal_id = row["id"]
        if proposal_id in seen_ids:
            continue
        seen_ids.add(proposal_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)
        eligible.append((proposal_id, row.get("priority", 0), cost_cents))

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

    selected_ids = []
    skipped_ids = []
    remaining_cents = budget_cents

    for proposal_id, _, cost_cents in eligible:
        if cost_cents <= remaining_cents:
            selected_ids.append(proposal_id)
            remaining_cents -= cost_cents
        else:
            skipped_ids.append(proposal_id)

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