Files
group_fqcd_jr/docs/28-场外与推广域数据表登记.md
T
qyqy f7a666fb5a fix(env)+docs: 按架构师第二轮纠正 mypy 根因(环境版本);补场外/推广域表登记
架构师第二轮答复里有一条技术纠正是对的,我原归因错了:
- 我原判断"184 个 mypy 错是因为缺 SQLAlchemy 2.0 类型信息"——**方向对了一半、结论反了**。
  SQLAlchemy 2.0 自带 py.typed,根本不需要 sqlalchemy2-stubs(那是 1.4 用的)。
- 实测复现矩阵(决定性证据):
    SQLAlchemy 2.0.34 + mypy 1.14.1 → 173 错(我原来的环境)
    SQLAlchemy 2.0.34 + mypy 1.20.2 → 173 错
    SQLAlchemy 2.0.52 + mypy 1.14.1 →   6 错
    SQLAlchemy 2.0.52 + mypy 1.20.2 →   3 错
  ⇒ 主因是 SQLAlchemy 的**补丁版本**(173→6),mypy 版本是次因(6→3)。
- 已把环境升到 SQLAlchemy 2.0.52 + mypy 1.20.2(均在 pyproject 约束内),
  mypy 从 184 降到 **3 个错**(剩下的 3 个全在同事的 offsite 文件里,非本线代码)。
- 没有把 sqlalchemy2-stubs 写进依赖(采纳架构师明确要求)。
- 交接文档已重写该条,并留下"两个反面教训":不要装 1.4 的存根包;补丁版差异会造成量级差异,
  若要门禁稳定需把 SQLAlchemy 钉到具体补丁版(属公共约定,未擅自改)。

按架构师裁决补文档(他裁定:不动 docs/00,另立登记):
- 新增 docs/28-场外与推广域数据表登记.md:17 张表逐表登记(表名/来源迁移/归属域/当前行数),
  并做规则 8 的**两向边界核对**——场内代码零引用这 17 张表(config.py 里的 offsite_ 只是配置项名)、
  场外代码零写场内交易表
- docs/08 审计口径更新为「场内 51 + 场外/推广 17 = 68」,并新增"第四种坏状态"
  (alembic_version 已指向新 revision 但表没建)的处置说明
- 澄清一个易误读点:audit_schema.py 的期望集合是**动态推导**的(读 baseline_generated.sql
  + 扫描 alembic/versions/*.py),表数 51→68 是自动结果,**没有人手工改期望值**;
  代价是只增不减(DROP 表会报 missing 假失败)

测试:3 failed(1 既有 + 2 环境相关)/ 1218 passed;文档守卫 35 份无重号;
mypy 3 错(180 文件);结构审计 68 张表通过。
2026-09-11 20:00:56 +08:00

6.8 KiB
Raw Blame History

场外与推广域数据表登记(docs/00 基线的域外补充)

用途:docs/00-新数据库基线设计.md 冻结的是场内基金模拟交易域的基线(不可变,规则 1)。 同事那条线(袁聪)合并进来的 17 张表属场外基金运营域与推广域,不进 docs/00, 由本文单独登记,避免"基线"这个概念因为塞入独立域而失效。

维护约定:新增/删除这两个域的表时必须同步本文;本文是「68 张表从哪来」的唯一答案。 表数口径:场内 51 + 场外/推广 17 = 68(共 69 张含 alembic_version)。


1. 为什么另立文档(架构师裁决,2026-09-11)

依据 AGENTS.md 规则 8:

当前系统业务功能只针对场内基金模拟交易;场外基金运营流程独立,不得写入场内交易表。

⇒ 场外与推广是独立域。把它们塞进 docs/00 会让"基线"从"场内交易域的冻结定义" 变成"当前全部表",下次有人拿 docs/00 当依据时会错。因此:

文档 职责
docs/00-新数据库基线设计.md 场内交易域基线(不可变,51 张)
本文 场外/推广域(17 张)的登记与来源
docs/08-数据库结构审计基线.md 审计口径:场内 51 + 场外/推广 17 = 68
tools/audit_schema.py 期望值同为 68(已生效,见 §4)

2. 17 张表逐表登记

2.1 场外基金运营域(offsite_*,10 张)

表名 来源迁移 建立它的提交意图
offsite_fund_mail 20260910_offsite_fund 场外申购邮件记录(运营入口)
offsite_fund_attachment 20260910_offsite_fund 邮件附件(该域唯一有数据的表,见 §3)
offsite_fund_document 20260910_offsite_fund 识别后的业务单据
offsite_execution_plan_task 20260910_offsite_fund 执行计划任务
offsite_rule_result 20260910_offsite_fund 规则校验结果
offsite_query_record 20260910_offsite_fund NL2SQL 查询记录
offsite_notification 20260910_offsite_fund 对外通知
offsite_mail_cursor 20260910_offsite_worker 邮件 Worker 的游标状态
offsite_recognition_attempt 20260910_offsite_recognition_attempt 识别尝试追踪(OCR/LLM 各一次尝试)
offsite_field_correction 20260911_offsite_field_correction 人工字段纠正记录

2.2 推广域(promotion_*,7 张)

表名 来源迁移 用途
promotion_material_task 20260910_promotion_material 推广素材任务(主表)
promotion_material_version 20260910_promotion_material 素材版本
promotion_input_snapshot 20260910_promotion_material 生成输入快照(可复现)
promotion_attachment 20260910_promotion_material 素材附件(海报/PPT)
promotion_compliance_check 20260910_promotion_material 合规校验结果
promotion_review_record 20260910_promotion_material 审核记录
promotion_delivery_record 20260910_promotion_material 投递记录

2.3 迁移文件清单(11 个,含 6 个 merge/辅助)

建表相关:20260910_offsite_fund / _offsite_worker / _offsite_recognition_attempt /
          _promotion_material / _promotion_poster / 20260911_offsite_field_correction
合并链:  20260910_merge_heads / 20260911_merge_review_separation /
          20260911_merge_risk_heads(当前 head)
其他:    20260910_offsite_worker_identity / 20260911_drop_review_separation

⚠️ 两个环境都踩过的坑:本库曾处于"alembic_version 已指向同事的 revision, 但 offsite_*/promotion_* 表一张都没有"的状态(版本号跑了、表没建); 架构师那边则是"表没建、版本号也没跑"。两种坏状态都靠 alembic upgrade heads 收敛。


3. 当前数据量(2026-09-11 实测)

表 行数
offsite_fund_attachment 60
其余 16 张 0

说明:只有附件表有数据(同事调试/演示时落盘的附件)。这不是"该域已在生产运行"的证据, 也不代表其它表可以删——禁止删表(规则 3)。


4. 跨域边界核对(规则 8 的两向检查)

4.1 场内代码是否引用这 17 张表 → 否 ✅

app/ 下搜 offsite_|promotion_ 只有 12 处命中,全部是 app/core/config.py 里的环境变量名 (offsite_mailbox、offsite_allowed_senders 等),没有任何 SQL/ORM 级引用。 场内模型(app/model/fund.py 等)与只读契约(FUND_TABLES)都只覆盖 fin_*。

4.2 场外代码是否写场内交易表 → 否 ✅

在 app/service/offsite*.py 与 app/model/offsite*.py 里搜 fin_sim_order|fin_capital_flow|fin_cash_ledger|fin_transaction|fin_holding —— 零命中。 场外域只读写自己的 offsite_* 表。

⇒ 两个方向都不越界,符合规则 8。这一点在合并评审时是要点,故在此留档。


5. 对审计工具的影响(不是"有人偷偷建表")

$ .\.venv\Scripts\python.exe tools\audit_schema.py
schema audit passed: 68 business tables, no missing or unexpected tables

表数从 51 跳到 68 是同事那 11 个迁移的预期结果**,不是有人绕过基线偷偷建表。**

机制要说清楚(否则会被误读成"期望值被手工改过"):tools/audit_schema.py 的期望表集合 是动态推导的,不是一份手写清单:

def expected_tables() -> set[str]:
    tables = <从 alembic/baseline_generated.sql 正则提取 CREATE TABLE>
    for path in (alembic/versions/*.py):
        tables |= <从每份迁移里正则提取 CREATE TABLE>      # ← 17 张新表由此自动进入
    return tables

⇒ 期望值随迁移自动增长,没有人手工改过它。优点是不会漏;代价是它只增不减 —— 若将来有迁移 DROP 掉某张表,期望集合仍会包含它,审计会报 missing 的假失败。 真要删表时(记得规则 3:禁止删除已有表)需同步调整该工具。

⚠️ 若你那边 audit_schema.py 报 unexpected,先确认是"库里多表"还是"迁移没进来"—— 前者是绕过基线的违规,后者只是迁移没合。两者处置完全不同。


6. 与 docs/00 的关系(一句话)

docs/00 一个字段、一张表都没动(规则 1)。本文是它的域外补充登记, 两者合起来才是"当前库里的全部表":

docs/00(场内 51)  +  本文(场外/推广 17)  =  68 张业务表

登记时点:2026-09-11 登记依据:现库 information_schema 实测 + alembic/versions 逐文件核对 + tools/audit_schema.py 的期望值推导机制核对。