Files
group_xinghuo_jinrong/docs/交接文档-架构改进.md
T
GaoYiYuan_0626 497cee289f docs: 交接文档合并为单一入口 + 全仓指向统一到 交接文档.md §A/§B/§C
背景:交接文档的定位是「给 AI 接手用的入口」,此前三份分散(项目根 交接文档.md
+ docs/交接文档-基金转换.md + docs/交接文档-架构改进.md),且 docs/ 两份停留在旧版
(v1.0 / v1.1,不含 T-0~T-2b、609 passed、D20 实施等进度),新会话极易被误导。

改动:
- 三份合并为项目根 交接文档.md v3.0(545 行 = §0 公共层 + §A 风控主线 + §B 基金转换线
  + §C 架构改进线);该文件在 .gitignore:47 内,按用户要求不入库(交接文档只留本地)
- 全仓指向统一到 交接文档.md §A/§B/§C:AGENTS.md(含顶部新增「接手先读交接文档.md」)、
  docs/memory/{MEMORY,TODO,FRAMEWORK,ITERATION}、PRD-架构改进与稳定性加固、
  开发计划-架构改进、TODO-架构改进、开发计划-基金转换交易
- 两份 docs/交接文档-*.md 加「已废弃(2026-09-10)· 勿读」横幅并指向新入口,
  保留作历史留档(不删除)
- 记录事故:对 docs/ 下中文名文件使用 git rm 会静默抹除整个 docs/ 目录(复现 2 次、
  退出码 0),已零损失恢复;纪律写入 交接文档.md §0.4 与工作区记忆

无代码改动;pytest 609 passed / 3 skipped。
2026-09-10 15:04:13 +08:00

14 KiB
Raw Blame History

交接文档 · 架构改进与稳定性加固(给执行 AI)

⛔ 本文件已废弃(2026-09-10)—— 本线已结项,请勿据此开工

内容已全部并入项目根 交接文档.md §C(三线合并版唯一交接入口),且本文件停留在 v1.1(执行后回写), 不含 §7.2 七项手工冒烟 7/7 PASS、push 状态纠正(037ce7e 早已推送)、残留重灌复绿等结项记录。 ⚠️ 下方「commit 但不 push」「待收尾」等表述已过期。 正确入口:交接文档.md §C —— 本文件仅作历史留档,内容已过期,勿读。

版本:2026-09-09 v1.1(执行后回写) 用途:给执行代码改动的 AI(hy3)。读完本文即可开工,不需要重读全部代码。 代码基线:分支 risk-control-agent,HEAD 2d0e2fa,pytest 503 绿 本轮已完成的规划:PRD + 架构设计说明书 + 开发计划 + TODO + 两轮独立审核,全部已通过审核。


⚡ 当前状态(v1.1,2026-09-09 21:10 更新)

第 1、2 批代码已全部落地并提交 037ce7e,pytest 实测 510 绿。未 push。

项 状态
T-101~T-109(文档勘误 + 标注 + 告警) ✅ 已完成
T-201.1 / .2 / .3(Redis 双层锁 + 测试) ✅ 已完成
T-202(中间件顺序守卫) ✅ 已完成
全量 pytest ✅ 510 passed(503 基线 + 6 锁测试 + 1 守卫)
commit ✅ 037ce7e(未 push)
手工冒烟(§7.2 七项) ❌ 未执行 ← 下一个会话优先做
第 3、4 批(合并后) ⏸ 按原计划不动

下一个会话开工三件事:① 跑 python -m pytest -q 复核 510;② 做 §7.2 七项手工冒烟(尤其"停 Redis"和"调换装饰器验证守卫变红");③ 补齐后报告用户,由用户浏览器目视确认再 push。

已改动文件(本次提交):

app/main.py                                  # DEEPSEEK_API_KEY 缺失告警(函数内延迟 import,无循环导入)
app/utils/authz.py                           # 越权审计失败日志补 trace_id
app/api/audit_middleware.py                  # 审计失败日志补 status/path/request_id
app/service/risk/redis_gateway.py            # +acquire_lock(SET NX EX) / +release_lock(Lua)
app/service/risk/locks.py                    # run_locked 改双层(Redis 为主、进程内为备)
tests/test_locks_redis.py                    # 新增 6 条(monkeypatch 假网关,不依赖本机 Redis)
tests/test_audit_middleware.py               # +1 条顺序守卫;_http_access 查询加 trace_id 列
docs/memory/MEMORY.md                        # A1 42→45 / A2 4→5
docs/项目框架设计/表设计/02-mysql-agent专用.sql # A3 5→6
docs/项目框架设计/架构设计-风控模块.md          # A4/A5 标注 + §5.8 G1/G2/G3

⚠️ 注意文件名:《架构设计说明书》实际落盘为 docs/项目框架设计/架构设计-风控模块.md(本次 A4/A5/G1~G3 标注写在这里);另有全量版 docs/项目框架设计/架构设计说明书.md(新增,9 章,40KB)。两者并存,改标注时别改错文件。


你的任务:按 TODO 执行代码改动。只做清单内的事,不做范围外改动。


0. 一句话任务

改 11 个原子项:9 项是文档修正和加告警(低风险),2 项是把进程内锁换成 Redis 分布式锁 + 加一个测试守卫。改完 pytest 必须仍全绿。


1. 五分钟背景

1.1 项目是什么

XingHuo 智能财富管家:金融四 Agent(客户财富 / 代理人 / 数据分析 / 风控)共用数据层与合规底座,四 Agent 不互调 LLM。

技术栈:Python 3.13 + FastAPI + LangGraph + MySQL 双库(jinrong_core 只读模拟 / jinrong_agent 业务)+ Redis + Milvus + Neo4j。

风控模块已完整交付(503 测试绿),马上要合并进 main 分支——这是本次改进的时间背景。

1.2 本次改进的来源

2026-09-09 做了全量架构梳理,发现 24 项待处理项。经两轮独立 AI 审核(第一轮审问题清单、第二轮审开发计划),无阻断级错误,方案核验成立。

用户拍板:补告警 + 换 Redis 分布式锁。

1.3 为什么要分批

因为"马上合并代码":合并前只做低风险的 9+2 项,DDL 类(唯一索引)和重构类(日志基建、权限收拢)一律放合并后。


2. 你要做的事(范围,严格按此执行)

批次 原子项 内容 风险 状态
第 1 批 A1~A5 修 5 处文档口径错误 极低(纯文档) ✅
G1~G3 补 3 项"非缺陷"设计标注 极低(纯文档) ✅
C4 无 key 启动告警(加一行日志) 低 ✅
C3 相关 审计降级日志补 trace_id(2 处) 低 ✅
第 2 批 B6 Redis 分布式锁(核心改动) 中 ✅
B2 中间件顺序测试守卫(新增测试) 低 ✅

详细验收标准:《docs/项目框架设计/TODO-架构改进.md》(逐项可勾选,照着做即可)

不要做的(第 3、4 批,合并后再说):

  • ❌ 加 agent_message 唯一索引(DDL,需先清洗历史数据)
  • ❌ 限流 EXPIRE 改造
  • ❌ core_ro DB 只读账号(需运维)
  • ❌ 支持 convert 交易(接口协议变更,待产品确认)
  • ❌ 日志基建、权限收拢、model 层启用、注册表合并
  • ❌ 意图识别升级、R-05 动态评分

3. 必读文档(按优先级)

顺序 文档 看什么
1 本文(交接文档) 全局、坑、禁止事项
2 docs/项目框架设计/TODO-架构改进.md 执行清单,照着勾选
3 docs/PRD/PRD-架构改进与稳定性加固.md 做什么、为什么、验收标准
4 docs/项目框架设计/开发计划-架构改进.md 怎么做(代码设计、降级策略、风险)
5 docs/项目框架设计/架构设计说明书.md 架构现状(必要时查)
6 docs/项目框架设计/改进方案评审-问题清单与对比.md 24 项问题全景(必要时查)

4. 已冻结的设计决策(不能改)

这些经过两轮审核,改了会破坏已验证的方案:

4.1 Redis 锁:双层降级,三条规则不可改

run_locked(key, fn)
   ├─ Redis 抢到锁          → fn(locked=True),finally 释放
   ├─ Redis 等待超时        → fn(locked=False)   ← 与原语义一致,不可改成抛异常
   └─ Redis 不可用(任何异常)→ 退回进程内锁       ← 不可改成直接降级

"任何异常"包括:

  • ConnectionError(Redis 没起)
  • AttributeError(测试 FakeGateway 没有锁方法) ← 关键,见 §5.2

4.2 参数(已定,勿随意改)

参数 值 说明
LOCK_TIMEOUT_SECONDS 2.0 保持原值,不改
LOCK_TTL_SECONDS 30 二审从 10 上调(10 秒无实测支撑)
_LOCK_KEY_PREFIX lock: 与 sess:/ratelimit:/auth: 隔离
_RETRY_INTERVAL 0.05 抢锁重试间隔

4.3 契约不变

run_locked(key, fn) 签名与 fn(locked) 回调语义完全不变,三处调用点一行都不用改。

4.4 不放 ensure_trace() 兜底

B2 测试守卫要能"真的报警"。若加 ensure_trace() 兜底,顺序错了会被掩盖,trace_id 与响应头不一致,更难查。


5. 关键代码位置与坑

5.1 run_locked 调用点是三处(极易漏)

# 位置 key 保护对象
1 alert_service.py:180 agg:event:{customer_id}:{date} 交易事件预警聚合
2 alert_service.py:239 agg:suitability:{customer_id}:{product_id}:{date} R-02 适当性阻断预警
3 profile_l3.py:155 l3:{customer_id} L3 监测层

⚠️ 第 2 处最易漏(初版规划就漏过,被二审抓出)。它是 record_suitability_alert 的聚合锁,而 R-02 是全系统唯一能阻断交易的规则。漏改会让最关键路径失去并发保护。

5.2 测试不依赖本机 Redis

tests/test_integration_risk.py:6 明确写"redis_gateway fake(不依赖本机 Redis)"。多个测试用 monkeypatch.setattr(redis_gateway, "_gateway", FakeGateway()) 注入假网关。

已核查:所有 FakeGateway(在 test_main.py / test_audit_middleware.py / test_auth_jwt.py / test_chat.py / test_profile_l3.py / test_risk_api.py 等)均无 acquire_lock / release_lock,也无 __getattr__。

→ 调用会抛 AttributeError → 你的代码必须归为"Redis 不可用"→ 退回进程内锁。这是设计,不是 bug。

5.3 Redis 网关现状

app/service/risk/redis_gateway.py:单例 _gateway,set_gateway 注入点,get_gateway 惰性创建。已有 publish/delete/exists/set_ex/incr/rpush/lrange/ltrim/expire。你要新增 acquire_lock / release_lock,纯新增不动现有方法。

5.4 中间件顺序(B2 相关)

main.py audit 先注册(81 行)、trace 后注册(87 行)。Starlette add_middleware 用 insert(0)、build_middleware_stack 用 reversed → 数组越靠前越外层 → trace 在外层先执行。

调换两个装饰器 → audit 先跑 → current_trace() 空 → 全站审计静默丢 trace_id,不报错。这就是要加测试守卫的原因。

5.5 TTL 引入的新失败模式(已知,接受)

进程内锁拿到后永不过期;Redis 锁有 TTL,若临界区耗时超 30 秒会自动解锁,另一实例可抢到。

这是 TTL 的固有代价,兜底是:L3 有数据库乐观锁、预警聚合有"锁内重查锚点",最坏是重复 pending 单,非数据损坏。已写入风险表,不要试图消除它(消除就会变成"进程崩溃后死锁")。


6. 实施顺序

1. 跑基线        python -m pytest -q      记录数字(应 503)
2. 第 1 批       T-101 → T-109(文档 + 2 处告警)
3. 跑测试        确认仍 503 绿
4. 第 2 批       T-201(Redis 锁)→ T-202(测试守卫)
5. 跑测试        确认仍 503 绿,新增测试已计入
6. 手工冒烟      见 §7
7. commit        **不 push**

建议:T-201 单独一个 commit,T-202 单独一个 commit,便于回滚。


7. 验收方式

7.1 自动化

python -m pytest -q          # 必须全绿,用例数 ≥ 503

7.2 手工冒烟

# 操作 期望
1 清空 .env 的 DEEPSEEK_API_KEY → 启动 日志出现降级告警,不阻塞启动
2 恢复 key → 启动 无该告警
3 POST /api/simulate/trade 阻断 + 放行各一次 行为与改动前一致
4 检查预警聚合 仍"同客户同日仅一张 pending 单"
5 停 Redis → 跑一次交易 业务仍可完成(退回进程内锁)
6 恢复 Redis → 再跑一次 行为与停服前一致
7 调换 main.py 两个装饰器 → 跑 T-202 测试 测试变红(证明守卫有效)→ 恢复

7.3 完成判定

  • FR-01~FR-06 验收标准逐条通过(见 PRD §3)
  • pytest 全绿且 ≥ 503(实测 510)
  • 未新增配置项、未新增依赖、未改路由
  • commit 但不 push(037ce7e),等用户在浏览器目视确认
  • §7.2 七项手工冒烟(未执行) —— 这是目前唯一缺口

8. 禁止事项

8.1 项目五条红线(碰了就是事故)

  1. Core 表只读
  2. 审计表只 INSERT
  3. 不自动冻结
  4. 不自动改风险等级
  5. 仅 R-02 可阻断交易

8.2 本次改动纪律

  • ❌ 不做清单外的改动(看到别的问题记下来,不要顺手改)
  • ❌ 不改 run_locked 对外签名
  • ❌ 不改三处调用点的调用方式
  • ❌ 不新增第三方依赖(redis 库已在 requirements.txt)
  • ❌ 不新增配置项(若决定配置化 LOCK_TTL_SECONDS,须同步 .env.example)
  • ❌ 不改路由(若改,必须同步 tests/test_main.py::test_all_routers_mounted 路径清单)
  • ❌ 不 push(commit 即可,等用户目视确认)

9. 项目特有坑(踩过的)

  1. 系统 Python 3.13.14(C:/Users/YUAN/AppData/Local/Programs/Python/Python313/python.exe)装了依赖和 pytest;managed 3.13.12 没装。用系统 Python 跑测试和 uvicorn。
  2. 本机 .env 已配置、bootstrap ①~⑤ 已执行,勿重做。
  3. 演示库重灌两步缺一不可:scripts/core/reset.ps1 + scripts/demo/prepare_risk_demo.sql。只跑第一步 → 33 客户中 27 人风评过期,会误判为 bug。
  4. sqlite 不支持绑定 Decimal:测试里插 core_trade.amount 须转 float。
  5. Milvus 数据路径必须纯英文(faiss 不支持中文路径),已配 C:/Users/YUAN/.jinrong/milvus/。
  6. 文档里的旧数字不可信:注入词表 42(应为 45)、Tool 4 个(应为 5)、专用表 5 张(应为 6)——这些正是本次 T-101~T-103 要修的,改代码时别拿旧数字当依据。

10. 完成后

已完成的回写(v1.1):

  1. 更新 docs/项目框架设计/TODO-架构改进.md:T-101~T-202 全部勾选,实测用例数改为 510(原记录写 511 有误,实际新增 6 锁 + 1 守卫 = 7 条)
  2. 更新本交接文档:新增"当前状态"块、§2 状态列、§7.3 勾选
  3. 在 docs/memory/2026-09-09.md 追加实施记录 —— 待补
  4. 未 push(037ce7e),等用户目视确认

下一个会话的收尾动作:

  1. 跑 python -m pytest -q 复核 510 绿
  2. 做 §7.2 七项手工冒烟,逐条在 TODO 里勾选
  3. 把冒烟结果写进 docs/memory/2026-09-09.md
  4. 报告用户 → 用户在浏览器目视确认 UI 后才允许 push;push 后打里程碑 tag

11. 有问题怎么办

  • 发现文档与代码不符 → 以代码为准,并在 TODO 备注里记下差异
  • 发现清单外的严重问题 → 不要顺手改,记下来报告用户
  • 对设计有疑问 → 查《开发计划-架构改进.md》对应章节;仍不明确则停下问用户,不要猜