Files
group_xinghuo_jinrong/docs/memory/2026-09-10.md
T
GaoYiYuan_0626andWorkBuddy 3244922a55 基金转换 T-3:core_ro 新增 5 个只读方法 + share_lot_repository 读侧
- core_ro 新增 get_nav_as_of(D10) / get_redeem_fee_rules / list_share_lots(S1 确定性排序)
  / sum_remain_qty(仅 >0) / get_holding;不动 get_latest_nav 与 list_trades_range 白名单
- 新增 share_lot_repository:core_share_lot 读侧 FIFO 贪心选批 + 汇总,排序复用 core_ro 的 ORDER BY(D18 单一副本)
- 新增 tests/test_share_lot.py 15 用例;pytest 全量 624 passed / 3 skipped(基线 609,零回归)
- 同步开发计划 §5.1 执行记录与交接文档 §B 状态(v1.5 / T-3 ✅ / 基线 624)

Co-Authored-By: WorkBuddy <workbuddy@tencent.com>
2026-09-10 15:42:55 +08:00

15 KiB
Raw Blame History

2026-09-10 工作日志

本日两条线:架构改进线收尾闭环(本文主体)+ 基金转换线第 4 步开发计划待启动。


一、接手与状态核对(会话起始)

读入:docs/交接文档-基金转换.md(v1.0)· docs/memory/MEMORY.md §0 · docs/交接文档-架构改进.md(v1.1) · docs/项目框架设计/架构设计-基金转换交易.md §15/§15.1 · docs/memory/{TODO,ITERATION}.md · AGENTS.md。

基线复核:python -m pytest -q(系统 Python 3.13.14)→ 510 passed(9.93s)。

设计资产核对:tests/_ddl.py:50-54 的 core_holding 仍为 market_value/quantity 且无 PK —— 与 T-0 描述一致,架构文档无误。

⚠️ 核对中发现的两处「文档与实况不符」(以实况为准)

  1. 037ce7e「未 push」是过期表述。 实测 git ls-remote origin:refs/heads/risk-control-agent = fffb78a = 本地 HEAD; git merge-base --is-ancestor 037ce7e fffb78a → 成立。即架构改进线全部提交(含其后 5 个文档提交)早已推送。 本地 git branch -vv 显示 origin/risk-control-agent: gone 只是本地远程跟踪引用失效,非远程分支被删。
  2. 基金转换线 6 个设计文件全部 untracked(未纳入版本库):docs/PRD/PRD-基金转换交易.md、 docs/项目框架设计/架构设计-基金转换交易.md、基金转换-审查意见处置表.md、 评审待办-风控主架构与基金转换.md、docs/交接文档-基金转换.md、scripts/dev/calc_convert_demo.py。 → 用户拍板:先 commit 入库(只 commit,不 push)。

二、架构改进线 §7.2 手工冒烟(七项,全部代跑,2026-09-10)

用户授权「七项全部代跑」。所有临时改动跑完即恢复。

第 1 项 · 无 key 启动告警 ✅ PASS

  • 本机 .env 的 DEEPSEEK_API_KEY 本就为空(实测 raw_value_len = 0),故「清空」态即当前态。
  • uvicorn app.main:app(端口 8123)→ 1 秒就绪,/health → 200 {"status":"ok","env":"development"}。
  • 进程存活 → 告警不阻塞启动 ✓。
  • 日志命中:DEEPSEEK_API_KEY 未配置,对话将走降级回复(前缀 (LLM 未配置:请在 .env 设置 DEEPSEEK_API_KEY 后重启)),LLM 能力不可用(app/main.py:66-72)。

第 2 项 · 恢复 key → 无告警 ✅ PASS(口径替代,已留痕)

  • 替代说明:本机无真实 DeepSeek key,「恢复 key」一支改用非空占位值(sk-smoke-placeholder-not-a-real-key)。 告警分支只判 not settings.deepseek_api_key,不校验 key 有效性,故该替代足以验证条件分支。
  • 改后 key_present: True → 启动(端口 8124)→ /health 200 → 日志未出现该告警 ✓。
  • 顺带验证 trace 中间件:响应头 x-trace-id: trc-48349abc526e4055 / x-request-id: req-612a3f2acb8349d6 ✓。
  • .env 已还原,key_present: False(原状)✓。

第 3 项 · 交易阻断 + 放行各一次 ✅ PASS

场景 请求(debug 头 X-Debug-Role: risk_demo / X-Debug-Actor: STAFF-DEMO) 响应
阻断(SOP A-2) CUST-4001 / PROD-161725 / subscribe / 20000 blocked=true,block_response_code=SUIT_AGE_CONFIRM,needs_branch_confirm=true,rule_refs=["FM-01"]
放行(SOP A-3) CUST-3001 / PROD-510300 / subscribe / 500000 blocked=false,triggered_rules=["RISK-001","RISK-002"],alert_ids=["ALT-20260910-7BCBBC94"]

与 SOP 记录的预期逐字一致。 库内核验:

  • core_trade:阻断单 TRD-20260910-C1D8AA26 未落库 ✓;放行单 TRD-20260910-FE545DF0 已落库(confirmed, 500000.00)✓
  • risk_suitability_log:CUST-4001 is_blocked=1 ✓;risk_alert 出 suitability 单 ALT-20260910-652280E1(pending_review, score 90)✓
  • audit_log:suitability_block / suitability_alert_created、trade_request / suitability_blocked(rule_id=SUIT_AGE_CONFIRM)、 trade_request / trade_accepted(放行)、risk_judgement / alert_created ✓

第 4 项 · 预警聚合行为不变 ✅ PASS

SOP A-4:CUST-9527 / PROD-510300 / subscribe / 1000 连发 4 笔:

笔次 triggered_rules alert_ids
1 [] []
2 [] []
3 ["RISK-003"] ["ALT-20260910-C8600425"]
4 ["RISK-003"] ["ALT-20260910-C8600425"] ← 与第 3 笔同一张单(并入,非新建)

库内核验:

  • risk_alert CUST-9527 当日 pending_review 单数 = 1 ✓;payload.events 长度 = 2 ✓
  • audit_log 呈 alert_created(1184) → alert_appended(1187)` 序列,聚合语义在审计层可证 ✓
  • 4 笔交易全部落库(TRD-20260910-B66CB0D8 / B39E1456 / 83D58A41 / 79EDC16E)✓

注:risk_alert.status 实际取值为 pending_review(文档口头简称「pending」)。首次核库我按 status='pending' 查得 0 条, 系断言写错而非系统问题,修正后为 1 ✓。

第 5 项 · Redis 不可用 → 退回进程内锁 ✅ PASS(口径替代,已留痕)

  • 替代说明:本机 Redis 为 redis-server.exe(PID 7716,Services 会话),无文档化启动方式、redis-server 不在 PATH、 sc.exe 被本机安全策略拉黑,杀掉后无法保证原样拉起(且 FLOW.md 明示其非权威数据源)。 改用 REDIS_URL=redis://127.0.0.1:6399/0(死端口):应用侧抛 ConnectionError,与真宕机同一条代码路径 (redis_gateway._ensure() → 命令异常 → locks._acquire_redis 的 except Exception → unavailable → 进程内锁),且完全可逆。
  • 结果:启动不被阻塞(1s,/health 200)→ 交易返回 blocked=false,alert_ids=["ALT-20260910-7BCBBC94"],业务照常完成 ✓
  • 日志明确出现 2 次 Redis 锁不可用,退回进程内锁: lock:agg:event:CUST-3001:2026-09-10(alert_service 聚合锁)、lock:l3:CUST-3001(profile_l3 L3 锁)✓
  • 底层异常:redis.exceptions.ConnectionError: Error 10061 connecting to 127.0.0.1:6399,被正确吞噬未上抛 ✓

第 6 项 · Redis 恢复 → 行为一致 ✅ PASS

  • redis.Redis.from_url(settings.redis_url).ping() → True(redis://127.0.0.1:6379/0)。
  • 同笔交易 → blocked=false,alert_ids=["ALT-20260910-7BCBBC94"](并入同单)✓
  • 日志中 退回进程内锁 命中 0 行 → 确实走 Redis 锁路径,未降级 ✓
  • triggered_rules 由 ["RISK-001","RISK-002"] 变为 +RISK-003:CUST-3001 当日累计至第 3 笔触发频次规则, 属预期累积行为,非不一致。

第 7 项 · 调换装饰器验证 T-202 守卫变红 ✅ PASS(本项价值最高)

守用例:tests/test_audit_middleware.py::test_audit_middleware_runs_inside_trace_middleware:210。

步骤 结果
① 基线 1 passed(绿)
② 调换 main.py 两装饰器(trace 先注册 → 变最内层;audit 后注册 → 变最外层) 已调换,行序:trace_middleware@89 / audit_middleware_entry@117
③ 跑守卫 1 failed ✓ 变红
④ 失败断言原文 AssertionError: audit 若先于 trace 执行,此处会静默为空 / assert '' @ test_audit_middleware.py:221
⑤ 还原 sha256 前后同为 d9d7559445dffd2a4576cdc5454030d3acae5fd4c076de8daa5a35f53802510a → 字节级一致 ✓
⑥ 再跑守卫 1 passed(转绿)✓
⑦ 现场核对 git status --short app/main.py 空、无残留 *.smoke.bak ✓

→ 守卫确实能抓住「audit 先于 trace 执行 → 全站审计静默丢 trace_id 且不报错」这一回归。设计意图达成。


三、冒烟副产物与现场恢复

3.1 集成测试失败(防护行为,非回归)

冒烟后在真 MySQL 上跑全量:507 passed / 3 failed,全部落在 tests/test_integration_risk.py:

  • _assert_a3_clean → CUST-3001 今日已有 confirmed 交易(影响 RISK-002 累计/RISK-003 频次口径)(我的 TRD-20260910-FE545DF0)
  • _assert_a4_clean → CUST-9527 今日已有 confirmed 交易(A-4 频次计数失真)(我的 TRD-20260910-B66CB0D8)
  • test_a7_handle_state_machine_compliance_forbidden → 级联 KeyError: 'a3_alert_id'

→ 这正是核查单⑥「演示/测试同日交叉防护」前置断言在按设计工作(交接文档已预警)。

3.2 演示库重灌(用户拍板:现在重灌)

按 docs/项目框架设计/演示SOP-风控模块.md §2 脚本化方式执行(MYSQL_PWD 传密码,避开 reset.ps1 交互 -p 卡死):

  1. DROP DATABASE IF EXISTS jinrong_core; DROP DATABASE IF EXISTS jinrong_agent;
  2. 依序灌 11 个 SQL:scripts/core/00~06 → 表设计/01-mysql-共用底座.sql → 表设计/02-mysql-agent专用.sql → scripts/agent/seed-aml-list.sql → scripts/demo/prepare_risk_demo.sql
  3. python scripts/sync/sync_advisor_rel.py

完成标志三项全部吻合:AML 名单 8 条 · prepare_risk_demo 7 行测评(expires_at 剩余 275 天)· sync_advisor_rel upserted 33 rows。

3.3 全量复跑(用户要求「改完后再跑一次」)

510 passed, 656 warnings in 9.52s → 复绿 ✓

现场状态:.env 已还原(key 为空、REDIS_URL 为 6379)✓ · app/main.py 字节级还原且 git 无改动 ✓ · 无残留 .smoke.bak ✓。


四、回写清单

文档 改动
docs/项目框架设计/TODO-架构改进.md T-107 手工冒烟勾选 + 完成判定块三勾 + 状态块改「全部闭环」+ push 状态纠正
docs/交接文档-架构改进.md v1.1 → v1.2;状态块重写(push 纠正 + 两处替代口径留痕);§7.3 全勾;§10 重写为结项
docs/交接文档-基金转换.md §9「另一条线的遗留」改为已闭环,纠正 push 表述
docs/memory/MEMORY.md §0 末尾「待办两条线」改为「架构改进线已结项」+ push 纠正常见坑
docs/memory/TODO.md 模块侧开放项「架构改进线 · 收尾」勾选并附七项证据摘要
docs/memory/ITERATION.md 新增 2026-09-10 架构改进线收尾闭环 迭代行
docs/memory/2026-09-10.md 本文件(新建)

五、下一步

架构改进线:结项,无待办。(可选:push 后打里程碑 tag,待用户拍板)

基金转换线:第 4 步「产出开发计划」 —— 输入已齐备: docs/项目框架设计/架构设计-基金转换交易.md §15(任务映射 T-0~T-13)+ §15.1(依赖拓扑与并行分组)+ §12(风险表); 产出落点 docs/项目框架设计/开发计划-基金转换交易.md(待创建)。


六、交接文档合并为单一入口 + 全仓指向统一(2026-09-10 晚)

6.1 用户指令与判定

  • 指令:「由版本库的交接文档为主,这两个交接文档你合并成一个新的放到这次更新」+ 指向项目根 交接文档.md。
  • 追加纠正:「统一一下,不是早都说过交接文档是给你 AI 接手用的吗」 —— 交接文档的定位 = AI 接手入口,所以全仓指向必须唯一,且绝不能指向过期文件,否则新会话会被误导。 (docs/ 下两份留档停在 v1.0 / v1.1,不含 T-2/T-2b、609 passed、D20 实施等进度 —— 是个真实陷阱。)

6.2 落地

项目根 交接文档.md → v3.0(545 行),三线合并为单一入口: §0 公共层(项目是什么 / 铁律与禁止事项 / 开发运行手册 / 已知坑 10 条 / 发现问题怎么办)· §A 风控模块主线(原主干)· §B 基金转换线(含工作区最新版 v1.4)· §C 架构改进线(含工作区最新版 v1.2)。 最大价值:这两份工作区最新版从未提交,随时可能丢,现已完整固化。

全仓 10 处指向统一 → 交接文档.md §A/§B/§C: AGENTS.md(含顶部新增「⚡ 需要接手/开工先读交接文档.md」)· docs/memory/{MEMORY,TODO,FRAMEWORK} · docs/PRD/PRD-架构改进与稳定性加固.md · docs/项目框架设计/{开发计划-架构改进,TODO-架构改进,开发计划-基金转换交易}.md。

两份 docs/交接文档-*.md 保留为历史留档,顶部加醒目横幅:「本文件已废弃(2026-09-10)—— 请勿据此开工, 正确入口 交接文档.md §B/§C,内容已过期,勿读」 —— 不删除(保留仓库历史),但明确失效。

未入库:交接文档.md 在 .gitignore:47 内,用户确认「不进提交」。

6.3 ⚠️ 事故:git rm 静默抹除整个 docs/(复现 2 次,已零损失恢复)

  • 现象:git rm(带不带 -f 均如此)删除 docs/ 下两个中文名文件 → docs/ 全部 54 个文件从工作区消失, 命令返回退出码 0 不报错。
  • 定位:① ls/find/Read 三方确认真实删除;② git checkout HEAD -- docs/ 完整还原 54 文件(索引与 HEAD blob 完好); ③ 无自定义 hooks(core.hooksPath 空);④ 同一中文路径 ls 完全正常 → 触发条件就是 git rm 本身; ⑤ 换 纯 rm -f <精确路径> → 正常。
  • 损失:零内容丢失(HEAD blob 完好)。代价:本轮引用修改被连带还原 2 次(重做 3 次)。
  • 纪律(已写入 交接文档.md §0.4 第 10 条 + .workbuddy/memory/MEMORY.md):
    • ❌ 本仓库禁止对 docs/ 下文件用 git rm;
    • ✅ 删文件用纯 rm -f <精确路径> + git add -A 记录删除;
    • ✅ 批量删除后立刻 find <dir> -type f | wc -l 复核,异常立即 git checkout HEAD -- <dir>。
    • 根因未查明,规避即可。

七、设计方法论固化为 skill + 记忆精简(2026-09-10 晚)

动机:项目记忆 MEMORY.md 与交接文档膨胀——13 问 / AIcoding 六步 / 独立审查协议 / 写计划 4 法 等项目无关的方法论每个项目都重写一遍,且挤占了项目状态信息。

落地:

  1. 新建用户级 skill design-doc-selfcheck(~/.workbuddy/skills/design-doc-selfcheck/SKILL.md)—— 固化:AIcoding 六步流程 · 设计自检 13 问(含 why/翻车案例)· PRD 独立 AI 审查协议(自包含包 + 只报告不改动 + 逐条判定)· 写开发计划 4 法 · 真实翻车案例库(4 处外部事实漏网 / 分类混用 / 公式副本 / 重置伴随数据 / 方言互斥)。
  2. 精简项目 MEMORY.md(205 行 → ~70 行):删除已入 skill 的方法论 verbatim,只留三条线状态、git rm 禁忌、交接文档定位、基金转换核心事实与业务口径、交易发起主体合规、D20 账号,并指向 skill。
  3. 交接文档 §B 顶部加 skill 指针:本线设计方法论已固化,避免重复维护。

效果:方法论跨项目可复用(新项目直接加载 skill);本项目记忆回到「状态 + 红线 + 口径」本职。