## Why

本次变更包含两个独立但相关的修复，均涉及轮询系统的核心可靠性：

**问题一（配置多匹配）**：当前 `PollingConfigManager.MatchConfig(card)` 的实现是"第一个匹配的配置直接返回，后续配置全部忽略"。这个设计在配置优先级体系下存在致命缺陷：**高 priority 的 catch-all 配置（如 id=29，priority=1，所有 interval 全为 NULL）会匹配所有卡，直接跳过更具体的配置（如 id=28，priority=25，card_status_check_interval=600），导致整个轮询系统失效**。

**问题二（调度器稳定性）**：轮询调度器（`Scheduler`）的主循环 `scheduleLoop` 没有顶层 panic recovery 和心跳上报机制。一旦 `processActivationTasks` 等路径发生 panic，整个调度 goroutine 静默终止——所有分片队列持续积压，但 Worker 进程看起来正常，无任何告警。同时，初始化完成前调度器无谓地空轮询；`initBatch` 失败时仅记录 Warn 掩盖了卡初始化缺失的严重性；Pipeline 执行只检查整体 error 而不逐条检查 cmder，部分卡初始化失败会静默丢失。

本次修复将匹配逻辑从"独占式单匹配"改为"组合式多匹配"，并同步修复上述调度器稳定性问题。

## What Changes

### 配置多匹配修复

- **修改 `MatchConfig` → `MatchConfigs`**：返回所有满足条件的配置（按 priority ASC 排序），而非第一个
- **修改 `matchConfigConditions`**：跳过所有 interval 均为 NULL 的配置（这些配置不应参与轮询匹配）
- **修改 `initBatch`**：对每种 task type，从所有匹配配置中选取最高优先级的非 NULL interval
- **修改 `enqueueCard`**（`lifecycle_service.go`）：同上，合并多配置的 interval
- **修改 `getEnabledTaskTypes` → 移除**：不再需要，`MergedTaskIntervals` 已包含启用的 task type 列表
- **重构 `calcInitialDelay`**：修改函数签名接受 `interval int` 参数，移除对 `*model.PollingConfig` 的依赖（因为新逻辑中 interval 来源是 `MergedTaskIntervals` 合并结果，不再属于单一 config）
- **修改 `requeueCard`**（`internal/task/polling_base.go`）：同上，使用 `MergedTaskIntervals` 替代 `MatchConfig` + `getIntervalByTaskType`
- **移除 `getIntervalByTaskType`**（`internal/task/polling_utils.go`）：`MergedTaskIntervals` 已提供按 task type 查 interval 的能力，该辅助函数不再需要
- **更新 `polling-config-manager` spec**：反映新的多匹配语义

### 调度器稳定性修复

- **新增 `scheduleLoop` 顶层 panic recovery**：主调度 goroutine 崩溃时记录 Error 日志，防止调度静默停止
- **新增 Scheduler 心跳机制**：每次 tick 写入 `polling:scheduler:heartbeat`（TTL=2×ScheduleInterval），供告警规则检测调度器存活
- **新增 Init 完成守卫**：`processShardSchedule` 首先检查 `initializer.IsCompleted()`，Init 未完成时跳过出队，消除启动期无效轮询噪音
- **`initBatch` 失败日志 Warn→Error**：批量初始化失败意味着部分卡未进入轮询队列，应使用 Error 级别
- **Pipeline 错误逐条检查**：`pipe.Exec()` 后遍历 `[]redis.Cmder` 逐条检查 `cmd.Err()`，记录具体失败的 ZADD 命令，防止部分卡初始化失败静默丢失
- **新增 `RedisPollingSchedulerHeartbeatKey()`**（`pkg/constants/redis.go`）：心跳 Key 统一管理

## Capabilities

### Modified Capabilities

- `polling-config-manager`：原有的"第一个匹配独占"语义改为"所有匹配配置 + 按 task type 选取最高优先级 interval"。这是**需求级别变更**（不仅是实现细节），需要更新 spec 中的 MatchConfig 描述和 Scenario。
- `polling-scheduler`：新增心跳上报、Init 完成守卫、顶层 panic recovery，调度器可观测性和稳定性提升。

## Impact

- **受影响文件**：
  - `internal/polling/config_manager.go`：新增 `MatchConfigs`、`MergedTaskIntervals`、`hasAnyEnabledInterval`
  - `internal/polling/initializer.go`：`initBatch` interval 选取逻辑；日志级别 Warn→Error；Pipeline 逐条错误检查
  - `internal/polling/lifecycle_service.go`：`enqueueCard` interval 选取逻辑，移除 `getEnabledTaskTypes`
  - `internal/polling/scheduler.go`：新增顶层 panic recovery、心跳写入、Init 守卫；新增 `initializer` 字段
  - `internal/task/polling_base.go`：`requeueCard` interval 选取逻辑（**稳态路径，每次轮询任务完成后执行**）
  - `internal/task/polling_utils.go`：移除 `getIntervalByTaskType`（被 `MergedTaskIntervals` 替代）
  - `pkg/constants/redis.go`：新增 `RedisPollingSchedulerHeartbeatKey()`
- **不受影响**：API 接口、DB schema、Asynq 任务提交逻辑（`queue_manager.go`）、handler 层
- **预期收益**：
  1. 配置系统按预期工作，id=28（suspended + card_status_check_interval=600）能正确对停机卡生效
  2. 调度器故障可被告警规则（检查心跳 key）及时发现，不再静默失效
  3. 启动期不再产生无效轮询噪音
  4. 卡初始化失败可见，不再静默丢失
