自检判据按基座二批新制度重写

- 旧判据全废(cap30/quiet12 启发式,07-27 实测 6/7 条假阳性)
- 保留 mkt_trade_date 检查(07-27 实测有效:自动降级污染日)
- 新增:members_total>600(大主题闸值)=基座制度回退 tripwire;
  不变量 n_quiet_stored=members_total−moved(旧制度日告警属预期)
- config: UPSTREAM_MEMBER_CAP 30→600(语义=闸值),UPSTREAM_QUIET_CAP 废弃
This commit is contained in:
zlt 2026-07-28 09:40:05 +08:00
parent 856372a0bb
commit 1232619525
3 changed files with 74 additions and 17 deletions

View File

@ -104,5 +104,6 @@ FROZEN_ROOT = os.environ.get("FROZEN_ROOT", "/app/data/frozen")
# 基座 graph_store.topic_context 的 Cypher 是 `LIMIT $cap`(默认 30且无 ORDER BY # 基座 graph_store.topic_context 的 Cypher 是 `LIMIT $cap`(默认 30且无 ORDER BY
# transmission.scan 落库时又有 `quiet[:12]`。命中这两个数就说明上游被截断了, # transmission.scan 落库时又有 `quiet[:12]`。命中这两个数就说明上游被截断了,
# 该行的 moved_ratio 建立在任意抽样上、覆盖也被展示逻辑锁住。 # 该行的 moved_ratio 建立在任意抽样上、覆盖也被展示逻辑锁住。
UPSTREAM_MEMBER_CAP = int(os.environ.get("UPSTREAM_MEMBER_CAP", "30")) # 07-28 语义更新:基座二批后 topic_context cap=1000、scan 大主题闸=600、quiet 全量落库。
UPSTREAM_QUIET_CAP = int(os.environ.get("UPSTREAM_QUIET_CAP", "12")) # 本值对齐基座"大主题闸"members_total 超过它 = 基座制度回退桥侧告警factors.py
UPSTREAM_MEMBER_CAP = int(os.environ.get("UPSTREAM_MEMBER_CAP", "600"))

View File

@ -158,6 +158,58 @@ backend/worker/worker-interactive/beat赶不上则明天跑同一清单
6. 桥机 18:45+`ls data/frozen/`(应有 2026-07-27/+ `tail data/cron_build.log` 6. 桥机 18:45+`ls data/frozen/`(应有 2026-07-27/+ `tail data/cron_build.log`
service not running 则 exec→run --rm service not running 则 exec→run --rm
7. 顺手07-24 的 17:30 sync 日志(受污染日根因) 7. 顺手07-24 的 17:30 sync 日志(受污染日根因)
**六节判收结果07-27 晚实测)**0✅新码三真2✅quiet_rows **410**(旧制 93/102
约 4.4×),不变量 12/12 全 tmkt_trade_date=07-24 如实打标max_m=99 未触闸
(整机制造 217 图成员中上市仅 99改1 的上市优先排序本就保住了它4✅钉死
07-23=(07-23,1675 行)movers 按日分明479 vs 755✅asof=07-17 写 1388 行、
live 无扰、核销=0闸生效1388≫邻近 live 行=当前池口径回填的预期形态)
**改1~4 机制层全部判收通过,二批关账**
**新仪表首夜逮住的两起事故(待办)**
A. **07-27 当日 mkt 无数据 → 定性=源侧迟到**07-27 晚二读):源 `MAX(timestamp)`
19:50 时已=2026-07-27而 17:30 sync 只见到 07-24顺手把它 727→2389 修复、
三 kind 补齐——sync 本身没坏,取"源侧最新"照章办事)。当晚修复链已给
sync 手动重拍→hotspot→transmission 同日重扫→桥补建,命令在对话)。
**结构性建议待拍板**beat 加"第二拍"sync-market如 09:55 UTC=17:55 CST
幂等删后插,首拍已有当日则等效空操作),基座 workers/tasks.py 一行。
佐证:`akg.sync_market_snapshot` 路由 **interactive 队列**tasks.py:43
⇒ 快照/传导的运行日志在 **worker-interactive** 容器,不在 worker——
六-3 的 grep 落空即此因。
B. **桥 cron 首夜失败(两层)**:①`data/` 为容器 root 属主,宿主重定向
Permission denied——日志已改 `$HOME` 路径;②**cron 时刻的宿主时区未定**
若桥机宿主是 UTC`40 18` 实为凌晨 02:40 CST我给错已认领——
`date` 判定后改 `40 10`UTC或保持 `40 18`CST
③**桥容器 date.today()=2026-07-28**run.py daily 裸取 today → 空跑出
2026-07-28 垃圾目录、四路 0 行)——容器时钟/TZ 待测;治本=cron 行加显式
`--date $(date +\%F)`(宿主取日,两种宿主时区下均正确),已并入修复命令。
遗留小项consensus 历史 07-16/07-22 空日(低优先)。
probe 三张读数提醒已钉 **07-30 周四 19:00**
**工作规约07-27 用户令):所有命令必须标注运行机器**——
【基座机 tlai4090·astock-kg】/【桥机 factorevaluation·akg-factor-bridge】。
**07-28 晨复盘(事故收口)**
- **A 关闭**修复链完成——07-27 mkt 三 kind 补齐2389/386/90根因=源迟到实锤
(次晨重拍即得完整当日)。**第二拍已落码**beat 表 sync-market-2nd17:55 CST
beat 配置本就是 Asia/Shanghai 时区,直接写 17:55——部署=基座 pull 后
force-recreate **beat**。**拍板记录07-27 传导台账不重扫**,保持 mkt_trade_date=07-24
的降级标记(重扫=今日图谱套昨日,成员性前视;降级标记正是采信规则的输入)。
- **B 关闭**:桥宿主=UTC 实锤 → cron 已改 `40 10`=18:40 CST+ 显式
`--date $(date +\%F)`"容器 07-28 之谜"消解——那批命令实际在次晨 UTC 零点后执行,
容器 UTC 无时钟病。frozen=07-24+07-27垃圾 07-28 已清)。桥代码为卷挂载
compose `.:/app`**pull 即生效无需 rebuild**。
- **C已修**:桥自检两条旧制度判据假阳性(">=30 撞 cap30" 6 条误报、
"quiet 存满 12" 7 条误报——已重写mkt_trade_date 检查保留07-27 实测有效,
桥打出"该日传导项不可信"=链路端到端贯通的实证members_total>600大主题闸值
才告警=制度回退 tripwire新增不变量检查 n_quiet_stored=members_totalmoved。
config.UPSTREAM_MEMBER_CAP 默认 30→600UPSTREAM_QUIET_CAP 废弃。
- 07-27 补建因子读数transmission 302 行(旧制 83/ heat 2387 / upside 992 /
event 531segment_members/edges 0 行=投影表未建,预期内(三批-4
- 07-28 晨间占位台账hotspot 32 候选 / transmission 12 候选 quiet 21809:25 建)
今晚 18:00/18:15 beat 删后插自然覆盖,无需处理。
- **今晚07-28=首个全自动夜**明晨验①mkt_daily 07-28 三 kind第二拍是否兜住
②传导台账 mkt_trade_date=07-28 ③桥 cron 10:40 UTC 首次正点frozen/2026-07-28
重新出现 + 因子行数非 0 + 新自检无假阳性)。
7. ✅(07-27 已回) mkt_daily stock 按日行数52/52/131/81/1674/1674/1675/1675/727 7. ✅(07-27 已回) mkt_daily stock 按日行数52/52/131/81/1674/1674/1675/1675/727
07-10~07-24缺 07-16、07-21。四个结论 07-10~07-24缺 07-16、07-21。四个结论
① stock 快照 = **池内快照非全市场**1674≈当时池规模——probe"有现价 727" ① stock 快照 = **池内快照非全市场**1674≈当时池规模——probe"有现价 727"

View File

@ -242,7 +242,7 @@ def build_transmission(start, end):
改用 distinct source 也更贴合传导模块自述的语义多源汇聚 = 传导逻辑更硬 改用 distinct source 也更贴合传导模块自述的语义多源汇聚 = 传导逻辑更硬
""" """
cols_new = ("scan_date, target, ts_code, n_sources, n_paths, moved_ratio, " cols_new = ("scan_date, target, ts_code, n_sources, n_paths, moved_ratio, "
"members_total, n_quiet_stored, mkt_trade_date") "members_total, moved, n_quiet_stored, mkt_trade_date")
try: try:
tr = db.read_pg( tr = db.read_pg(
f"SELECT {cols_new} FROM v_factor_transmission " f"SELECT {cols_new} FROM v_factor_transmission "
@ -273,9 +273,12 @@ def build_transmission(start, end):
def _warn_upstream_truncation(tr: pd.DataFrame) -> None: def _warn_upstream_truncation(tr: pd.DataFrame) -> None:
"""三个上游「静默失真」变成显式告警(评审 硬伤1、§6.2 """上游「静默失真」变成显式告警——07-28 按基座二批后的新制度重写判据
这些是基座侧的问题桥修不了**必须看得见**否则第一权重项在悄悄失真 基座二批后topic_context cap=1000scan 大主题闸=600quiet 全量落库
mkt_trade_date 落库旧判据members_total>=30 cap30 / n_quiet_stored>=12
撞截断在新制度下全是假阳性07-27 实测 6/7 条误报废弃
采信规则stale 剔除/打折/标记待三批-5 拍板当前全量采信只告警
""" """
if "mkt_trade_date" in tr.columns and tr["mkt_trade_date"].notna().any(): if "mkt_trade_date" in tr.columns and tr["mkt_trade_date"].notna().any():
bad = tr[tr["mkt_trade_date"].astype(str) != tr["scan_date"].astype(str)] bad = tr[tr["mkt_trade_date"].astype(str) != tr["scan_date"].astype(str)]
@ -284,20 +287,21 @@ def _warn_upstream_truncation(tr: pd.DataFrame) -> None:
f"scan_date 不符17:30 sync_market 晚点)——这些日的传导项不可信") f"scan_date 不符17:30 sync_market 晚点)——这些日的传导项不可信")
if "members_total" in tr.columns: if "members_total" in tr.columns:
hit = tr[pd.to_numeric(tr["members_total"], errors="coerce") hit = tr[pd.to_numeric(tr["members_total"], errors="coerce")
>= config.UPSTREAM_MEMBER_CAP] > config.UPSTREAM_MEMBER_CAP]
if not hit.empty: if not hit.empty:
n = hit["target"].nunique() if "target" in hit else len(hit) n = hit["target"].nunique() if "target" in hit else len(hit)
print(f" ⚠️ {n} 个环节 members_total >= {config.UPSTREAM_MEMBER_CAP}" print(f" ⚠️ {n} 个环节 members_total > {config.UPSTREAM_MEMBER_CAP}"
f"撞上游 topic_context 的 LIMIT cap —— moved_ratio 建立在**任意顺序**的" f"(基座大主题闸值)——基座制度回退或闸失效,查 transmission.scan")
f"抽样上Cypher 无 ORDER BY先修基座再放量") if {"n_quiet_stored", "members_total", "moved"} <= set(tr.columns):
if "n_quiet_stored" in tr.columns: mt = pd.to_numeric(tr["members_total"], errors="coerce")
hit = tr[pd.to_numeric(tr["n_quiet_stored"], errors="coerce") mv = pd.to_numeric(tr["moved"], errors="coerce")
>= config.UPSTREAM_QUIET_CAP] nq = pd.to_numeric(tr["n_quiet_stored"], errors="coerce")
if not hit.empty: bad = tr[(mt - mv) != nq]
n = hit["target"].nunique() if "target" in hit else len(hit) if not bad.empty:
print(f" ⚠️ {n} 个环节 quiet 存满 {config.UPSTREAM_QUIET_CAP} 条," n = bad["target"].nunique() if "target" in bad else len(bad)
f"撞 transmission.py 的 quiet[:12] 截断 —— 真实未动成员更多," print(f" ⚠️ {n} 个候选 n_quiet_stored ≠ members_total moved ——"
f"因子覆盖被展示逻辑锁住") f"quiet 截断复活或台账/视图不一致07-27 新制度起不该发生;"
f"若构建窗口含 07-24 及更早的旧制度日,此告警对旧日属预期)")
BUILDERS = { BUILDERS = {