feat: C5 FR-9 预警处置时效升级(RISK-007,P0)

- 仓储:新增 list_pending_alerts_all / update_alert_escalation(统一读改写 payload,
  升级标记独占写入,status/handler_* 列不碰;_parse_alert 补 created_at/handled_at
  字符串→datetime 解析,兼容 sqlite 原生 DDL)
- escalation_service.scan_and_escalate:扫描判级(普通 4h/24h、AML 1h/4h 短通道)、
  幂等闸门(仅升不降)、先持久化再推送、按 (customer_id,level) 降噪合并一次推送、
  通知链累积(L1 含 risk_manager / L2 含 compliance)、逐单+任务级审计
- scripts/cron/escalation_scan.py:15min 定时扫描壳(sys.path 引导 + new_trace + JSON 摘要)
- 对话线 query_overdue_alerts Tool + 注册表 + 意图词(置于 alert_query 之前)+ summarize 分支
- C5 前置:seed STAFF-31001/31002(risk_manager) + deps 矩阵放行 + chat.py 显式 deny +
  risk.py 台账全量只读分支;JWT 手册 §5.3/§5.4/§6.1 增补 risk_manager
- 测试:conftest 回拨 fixture + test_escalation_service(9) + risk_api/manager(5) +
  chat deny(1) + chat_tools overdue(2);全量 470 绿(453+17)
This commit is contained in:
2026-09-07 19:28:04 +08:00
parent fe4801bc0a
commit 90d0660b44
15 changed files with 720 additions and 3 deletions
@@ -227,6 +227,7 @@
| `advisor` | `agent:advisor:chat`, `profile:l1:read`, `profile:l2:read`, `profile:l2:write`, `profile:l3:read`, `core:*:read:assigned` |
| `analyst` | `agent:analyst:chat`, `profile:l1:read`, `profile:l2:read`, `profile:l3:read`, `core:*:read:scoped`, `sql:execute:readonly`, `risk:alert:read` |
| `risk_officer` | `agent:risk:chat`, `profile:l1:read`, `profile:l2:read`, `profile:l3:read`, `profile:l3:write`, `risk:alert:write`, `risk:suitability:write`, `core:*:read:all` |
| `risk_manager` | `risk:alert:read`, `core:*:read:all` | 风控经理:HTTP 台账全量只读,**无处置权、对话线经 chat 层显式拒绝**(PRD 4A.1 / C5 前置) |
| `compliance` | `audit:read:all`, `agent:advisor:audit`, `compliance:hit:read` |
| `ops` | `agent:advisor:stats`, `audit:read:aggregated` |
| `service_risk` | `agent:risk:suitability_check`, `risk:suitability:write`, `profile:l1:read`, `profile:l2:read`, `audit:write` |
@@ -240,7 +241,7 @@
| `customer` | `customer` | `customer` |
| `advisor` | `staff` | `advisor`, `compliance`, `ops` |
| `analyst` | `staff` | `analyst`, `compliance` |
| `risk` | `staff`, `service` | `risk_officer`, `service_risk` |
| `risk` | `staff`, `service` | `risk_officer`, `service_risk`, `risk_manager` |
---
@@ -256,6 +257,7 @@ JWT 通过后,**任何涉及 `customer_id` 的读写** 必须执行归属校
| `advisor` | 客户画像 / 持仓 / 会话 | `customer_advisor_rel` 存在 `advisor_id=sub AND customer_id=? AND rel_status=active` | `AUTH_403_NOT_ASSIGNED` |
| `analyst` | 客户级明细 | 走 **数据权限目录**;无明细权限则 **仅允许聚合 SQL**(`COUNT`/`GROUP BY`,结果 ≥ k-匿名阈值) | `AUTH_403_SCOPE` |
| `risk_officer` | 全量客户 | 允许读全部;写仅限 L3 / 预警 / 适当性 | — |
| `risk_manager` | 全量客户 | **仅读**预警台账(`risk:alert:read`,无 `risk:alert:write`);对话线(chat)经 `app/api/chat.py` 显式 `deny(AUTH_403_ROLE)` 拒绝,强制走 HTTP 台账 | — |
| `compliance` | 审计 / 会话 | 可跨客户读 **审计类表**;读 `agent_message` 需 `audit:read:content` 额外权限 | `AUTH_403_AUDIT_SCOPE` |
| 跨 Agent 读会话 | `agent_session` | 角色只能读 **同 agent_type** 会话;合规除外 | `AUTH_403_SESSION_AGENT` |