框架

架构风险审计待办 · v5.2.3 一致性加固(2026-09-26)

A-1 熔断计数器跨任务单调累积、永不复位

optimization · 资产·机制 · optimization/待办与交接/架构风险审计待办_v5.2.3_2026-09-26.md · 17100 B

架构风险审计待办 · v5.2.3 一致性加固(2026-09-26)

来源:2026-09-26 高级架构风险审计官【纯只读审计】(3 个高层视图 + 定向取证,未改任何文件)

性质:审计结论 → 可执行待办(本文件只描述要做什么,本身不执行修改)

状态:✔ 已执行(2026-09-26,批次 A→B→C→D 全部落地;见 00 驾驶舱(投资MOC).md §九 · v5.2.3 条目)

收官验收(2026-09-26 实测):state_digest --guard --mode EXEC_SUGGESTIONS = {"loop":4,"cost_est":0.15,"break":false,...,"cost_wired":true} rc=0|arch_check 11/11 ✔(md=213 / 出链 750 / 死链 0 / 孤儿 0)|doc_sync_check --strict rc=0|测试逐类前台全绿 64 项 / 13 类|技能 v1.7.2(镜像 md5 1c27c84b)|备份 /var/minis/shared/backup/DUCKERRY_pre_v523_20260926/(pre 全量 + post_B/ post_C/ post_D/ + md5_after_*.txt)

目标产出:系统版本 v5.2.3(熔断/监护/一致性加固)—— 已达成(arch_check 11/11(本待办撰写时为 10/10,C 批新增第 11 项) + doc_sync_check --strict rc=0 + 测试全绿)

仓库:/var/minis/mounts/DUCKERRY_Warehouse

审计时的机械基线:arch_check 10/10 ✔(md=212 / 出链 748 / 死链 0 / 孤儿 0 / 第 10 项 0 个点不到);doc_sync_check --strict rc=0(面板 85 行 / target 2026-09-25);state_digest --guard → {"loop":13,"cost_est":0.0,"no_progress":0,"break":false} rc=0;技能与仓库镜像 md5 一致 5ca15c2c


〇、执行纪律(红线,违反即停)

  1. 备份先行:动手前全量备份到 /var/minis/shared/backup/DUCKERRY_pre_v523_20260926/(至少 scripts/、state/、00 驾驶舱(投资MOC).md、框架/技能/、optimization/),并记 md5_before.txt。
  2. 一次一批:按 批次 A → B → C → D 顺序,每批独立回报后再进下一批;P0(批次 A)必须最先。
  3. 不动历史:不改 复盘/历史原始记录/、不改归档区、不删任何 *.bak*(沿用 F1 决策:保留不清理)、不改任何已有复盘正文。
  4. 不伪造数据:任何数值必须来自脚本输出;不确定的标 [待验证]。
  5. iSH 环境铁律:测试每次 shell_execute 只跑 1 类、前台、不重定向(并发/连续跑必被静默 kill);重脚本用 DK_DISABLE_MCAL=1。
  6. 熔断提示(本次审计重点):state_digest --guard 在批次 A 修好前已剩 2 步余量(loops=13/15)。若新对话开跑不久即 rc=3 且 reason 只有 loops=...≥15(而本任务实际步骤 ≤5),属已知假熔断——先执行批次 A 修复,再继续,不得据此中止任务或写 BUDGET BREAK。
  7. 收尾必绿:每批结束时 python3 scripts/moc_index.py → python3 scripts/arch_check.py(期望 10/10)→ python3 scripts/doc_sync_check.py --strict(期望 rc=0);任何一项 ✘ 先修再回报。

一、审计发现(证据已固化,无需重审)

P0(致命,1 条)

A-1 熔断计数器跨任务单调累积、永不复位

  • 位置:scripts/state_digest.py:222 b["loops"] = max(int(b.get("loops", 0)), a.step);阈值 MAX_LOOPS=15(--guard 分支 L199-205)
  • 证据:state/budget.json 实测 loops=13,history[].t 跨 2026-09-25→09-26 多个会话、mode 从 DAILY_REVIEW 变为 EXEC_SUGGESTIONS 均未重置;实测 --guard 输出 {"loop":13,...,"break":false} rc=0
  • 影响:下一次日常任务第 3 步即 rc=3 假熔断 → Agent 按 SOP 写 BUDGET BREAK 并放弃当日发布,而任务本身完全正常。安全方向失败,但直接打断每日发布流程。

P1(严重,4 条)

B-1 max_budget 熔断是死代码

  • 位置:scripts/state_digest.py:200(唯一读取方);技能 YAML max_budget: 0.5
  • 证据:全库 cost_est 只有读取、无任何写入方;实测 --guard 输出 "cost_est": 0.0 → 0.0 >= 0.5 永假
  • 影响:「两天 $200」事故的目标防线从未生效,当前唯一有效防线是被 A-1 破坏的 loops。

B-2 预测台账锁无超时、无逃生出口

  • 位置:scripts/predict_regime_conditional.py:180-189 fcntl.flock(lockf, fcntl.LOCK_EX) + LOCK_UN
  • 证据:无 LOCK_NB、无 timeout、无 CLI 开关;历史事故已有归档 数据/predictions/incident_20260916_concurrent_write.jsonl;数据/predictions/predictions.lock 为 0 字节残留(mtime 09-21)
  • 影响:持有者卡死 → 预测写入无限阻塞(即「GLM 卡在 locklocklock」场景);主线其它环节均有逃生开关(--no-bond/--no-aux/--no-wf/--no-recompute/DK_SKIP_*/DK_DISABLE_MCAL),唯独此处没有。

C-1 SOP 提示词与系统版本脱节 3 个版本

  • 位置:optimization/每日发布运行提示词_2026-09-23.md(自称 v5.0.1、仍标「新对话直接粘贴」)
  • 证据:文中 L209「arch_check 期望 9/9」、L218「完整测试 15 项」、§6.5「登记索引=强制步骤」;不含 state_digest --guard/--step、state/current.md 剪枝、--no-aux、pattern_abc、doc_sync 11 项(版本时点:v5.2.3 时 doc_sync 为 11 项;v5.3.2 / 技能 v1.7.5 起为 13 项,新增第 12/13 项——本行所述为 2026-09-26 审计时的事实,不改写)。另 optimization/继续任务提示词_2026-09-25_v5.2二级源与空头腿.md 亦漂移(写「44 项」测试,实测 47)
  • 影响:粘贴旧 SOP = 绕过熔断与状态外置、按 v5.0 口径验收,与驾驶舱 v5.2.2 / 技能 v1.7.1 冲突。

C-2 state/current.md 零监护(污染直入决策)

  • 位置:state/current.md;arch_check.py / doc_sync_check.py / moc_index.py 中 grep state/ 零命中
  • 证据:v1.7.0 SOP 要求「每 ≤3 步只读本文件」,但无任何自检解析它;state_digest 覆盖写无 .bak,budget.json.history 只存 hash,无法回看上一份摘要
  • 影响:Agent 误写 target/L0/L1 或写盘中断留半截文件 → 无告警、污染直接进入后续判断;自愈只能人工再跑 --step。

P2(建议,5 条)

D-1 AUTO 区块自愈能力不对称

  • AUTO:DATA:手改会被下次 fetch.py 整段覆盖(L348-358),标记缺失会回退插到「## 一、核心框架」前 → 自愈 ✔
  • AUTO:INDEX:fetch.py:575-580 标记缺失时只记 {"updated":false,"error":"缺少 AUTO:INDEX 标记"},moc_index.py 亦只打印错误不重建标记 → 索引永久停更(「写入了但点不到」复发)
  • 另:两类告警均只 warning 不阻断(设计如此,保留)

D-2 状态摘要内部自相矛盾(跨 run 证据混入)

  • 位置:scripts/state_digest.py:105 _tail(p, 400)
  • 证据:本次实测 state/current.md 同时含 doc_sync=True 与 ⚠ 排版同步检查: 3 项待同步(见上)——后者来自 数据/logs/fetch_c1_20260926.log:33 的历史 run 遗留行,而 数据/latest.json.doc_sync = {"ok": true, "issues": []}
  • 影响:Agent 会去重复修文档 → 浪费 loops(与 A-1 叠加加速假熔断)

D-3 一致性判据锚定已停用的文件命名族(假绿)

  • 位置:scripts/doc_sync_check.py:113-118 glob("optimization/系统架构优化报告_*.md")
  • 证据:最新命中 系统架构优化报告_2026-09-23_v5.0.md,而 09-24/25/26 报告已改名为「路径防呆…/v5.2…/v5.2.1…/仓库文件修改建议…」→ §九 版本记录对最新报告从未被校验

D-4 文档—代码口径漂移

  • 驾驶舱 L114、L605 写「债券腿子进程 240s 超时」,代码 scripts/fetch.py:37 实为 refresh_bond_leg(timeout=480)
  • 技能/提示词声明测试「44 项」,实测 tests/test_pipeline.py = 47 项 / 9 类(PipelineSafety / Paper / BondLeg / RegimeWf / DocSync / PathGuard / AuxSource / PatternAbc / PaperShortReduce)

D-5 冗余与维护成本

  • scripts/recompute3.py 零引用孤儿(fetch.py:152 哈希清单只含 recompute2/recompute4);scripts/legacy/ 8 个 + audit_evidence/scripts/recompute*.py 平行副本 + 内置 scripts/pandas_market_calendars/
  • 保留建议:治理层 4 脚本职责不重叠(arch_check 死链/孤儿/地图 ↔ doc_sync_check 跨文件数值 ↔ moc_index 可达性 ↔ state_digest --guard 熔断),不合并

二、已验证无风险(不要去"修"这些,避免无谓消耗)

维度结论证据
死链/孤儿/导航可达性无风险arch_check 10/10 ✔:md=212 出链 748 死链 0 孤儿 0;第 3 项 0 未引用;第 10 项 0 个点不到
跨文件数值一致性无风险doc_sync_check --strict rc=0;latest.json.doc_sync={"ok":true,"issues":[]}
AUTO 区块内容层防越权有效fetch.py:348-358 整段覆盖 + 标记缺失回退插入;doc_sync #2/#4 内容级比对
主线逃生出口完备--no-bond/DK_SKIP_BOND、--no-aux/DK_SKIP_AUX、--no-wf/DK_SKIP_WF、--no-recompute、DK_DISABLE_MCAL;债券腿 timeout=480 且失败永不阻断发布
二级源越权替换权威源无风险v5.2.1 报告 §一 回归断言:权威源有值绝不顶替;dkanalysis 用 upto[-1]==tkey;反推值必标 [待验证]
债券腿「盘中伪收盘」无风险update_bond_etf._is_session_final()(now_utc ≥ D 21:00Z)+ provisional_dropped 自愈剪除;当前 82 天,末行 09-25 TLT 79.32 / AGG 95.12
技能主副本 ↔ 仓库镜像一致双端 md5 5ca15c2cdc82df8a4281e308cdd7bc07(v1.7.1)

三、批次任务

批次 A(P0,必须最先)— 熔断状态机复位

A-1 修复(scripts/state_digest.py)

  • budget.json 增加分桶:"loops_by": {"<YYYY-MM-DD>|<MODE>": N};--step 只写当前桶,loops 顶层字段保留为「当前桶值」(兼容旧读法)。
  • 复位规则:--step 时若 mode 变化(b["mode"] != a.mode)或日期变化 → 当前桶从 0 起算、no_progress=0;不同 mode 不共享计数。
  • 新增子命令 --reset [--mode M]:显式把当前桶清 0(供用户/Agent 在确认真假熔断后使用),打印改动后的 budget.json 关键字段。
  • --guard 输出增加 "bucket" 字段(如 "2026-09-26|EXEC_SUGGESTIONS"),便于人工判定。
  • 一次性数据修复:现有 loops=13 迁移为 loops=0 + loops_by 保留历史桶(迁移前 cp state/budget.json state/budget.json.bak_pre_v523)。

A-1 验证

  • python3 scripts/state_digest.py --guard → loops 归零、break=false rc=0;
  • 连续两次 --step 1 --mode DAILY_REVIEW → 桶=1;再 --step 1 --mode EXEC_SUGGESTIONS → 新桶=1(互不影响);
  • 新增测试类 StateDigestTests(≥3 项:mode 变化复位 / 同日累计 / --reset 生效),逐项前台跑。

批次 B(P1)— 成本熔断接线 + 台账锁逃生

B-1(scripts/state_digest.py)

  • 二选一并明确记录:
  • (a) 接线:--step 新增可选 --cost <usd>,累加 b["cost_est"] = round(b.get("cost_est",0.0)+inc, 4);--guard 输出 cost_est;SOP 中说明「每步由 Agent 估算并传 --cost」。
  • (b) 降级声明:技能 YAML 把 max_budget: 0.5 标注为 max_budget: 0.5 # unwired(未接线,仅记录,不参与熔断),并写入驾驶舱 §九 已知口径。
  • 无论选哪条,不得留下"看起来有保护实际没有"的状态。

B-2(scripts/predict_regime_conditional.py)

  • flock(..., LOCK_EX | LOCK_NB) + 最多 5 次 × 2s 重试;仍失败 → 打印 LOCK_TIMEOUT: 台账被占用,已跳过本批追加,rc=0,并把 latest.json.predictions = {"appended": 0, "skipped": "lock_timeout"}(不阻塞发布、不写坏数据)。
  • 新增 --no-lock(无锁直写,仅排障用);--lock-timeout <sec> 可调。
  • 清理 数据/predictions/predictions.lock(0 字节、mtime 09-21):移入 数据/predictions/__obsolete__/,不要 rm。
  • 测试:PaperShortReduceTests 旁新增用例(锁占用时跳过且 rc=0),或复用既有类追加 1 项。

批次 C(P1)— 状态监护 + SOP 废止 + 口径对齐

C-1

  • optimization/每日发布运行提示词_2026-09-23.md 头部加醒目标记:> ⚠️ 已废止(v5.0.1,2026-09-23):请改用 框架/技能/duckerry-daily-review SKILL.md v1.7.1,并把「9/9 → 10/10」「15 项 → 实测 47 项」就地更正(或整文件移入 复盘/历史原始记录/ 并在驾驶舱留跳转)。
  • 技能 §1 顶部加硬规则:「任何手写提示词若未含 state_digest --guard 与 10/10 自检口径,一律视为过期,以 SKILL.md 为准」。
  • 继续任务提示词_2026-09-25_...md 的「44 项」→「以 grep -c "def test" tests/test_pipeline.py 实测为准」。

C-2

  • arch_check.py 新增 第 11 项「state/current.md 可解析性」:首行 # STATE · DUCKERRY;含 target=/gate=/L0=/L1=;doc_sync=True 时不得同时出现 待同步;尾部含 === 完成行。仅告警(rc 语义不变),并同步更新驾驶舱「arch_check 10 项 → 11 项」口径。
  • state_digest.py 覆盖写前 shutil.copy(CUR, CUR + ".bak");证据切片改为只取最后一条 === DUCKERRY … === 之后的段落(修 D-2)。
  • 技能 §0.3 补一句:「state/current.md 只允许 state_digest.py 写入;Agent 手工编辑视为违规,发现即重跑 --step」。

批次 D(P2)— 一致性加固与整洁度

D-1 moc_index._block_text() 找不到 AUTO:INDEX 标记时自动重建标记对(插在 §7 标题后)并写回,日志 索引标记缺失→已重建;fetch.py:575-580 分支改为调用该自愈函数。 D-2 已在批次 C-2 处理(证据切片)。 D-3 doc_sync_check.py 第 8 项改为扫描 optimization/*.md 全部取文件名内最大日期做 §九 校验(或加「§九 最新条目日期 ≥ optimization 最新 mtime 日期 −1 天」判据)。 D-4 驾驶舱 L114/L605 240s → 480s;技能/提示词测试项数改为实测口径。 D-5 scripts/recompute3.py 移入 scripts/legacy/;驾驶舱 §〇 架构表补一行「audit_evidence/ 与 scripts/legacy/ 为历史证据,不作为当前判据」。


四、DoD(完成判定)

  1. python3 scripts/state_digest.py --guard → loops 为本任务步数(不是 13+),break=false;
  2. python3 scripts/arch_check.py → 11/11 ✔(批次 C 后)或 10/10 ✔(批次 A/B 后);
  3. python3 scripts/doc_sync_check.py --strict → rc=0;
  4. 测试逐类前台跑全绿(PipelineSafety 10 / Paper 5 / BondLeg 5 / RegimeWf 3 / DocSync 4 / PathGuard 4 / AuxSource 6 / PatternAbc 4 / PaperShortReduce 6 + 新增类),并记录实际项数;
  5. 驾驶舱:§九 新增 v5.2.3 记录(本待办 4 批次)、§〇 架构表/系统概览按需更新、§〇·五 optimization/ 计数同步;
  6. 技能 duckerry-daily-review 升 1.7.2(或 1.8.0):记录熔断分桶复位、状态监护、锁逃生;同步仓库镜像并核对 md5 一致;
  7. 备份点与 md5 全部记录在回报中。

五、每批回报模板(≤15 行)

批次 X:改动文件(含 md5_before → md5_after)
核心变更:(每条 ≤1 行)
自检:arch_check ?/? ; doc_sync rc=? ; state_digest --guard = {...}
测试:逐类结果(类名 → OK/项数)
备份:/var/minis/shared/backup/DUCKERRY_pre_v523_20260926/...
遗留/待确认:

六、供新对话粘贴的最小提示词(执行阶段)

按 DUCKERRY_Warehouse 架构风险审计待办执行 v5.2.3 加固。
待办文件(必读,含全部审计证据):optimization/架构风险审计待办_v5.2.3_2026-09-26.md
仓库:/var/minis/mounts/DUCKERRY_Warehouse|技能口径:框架/技能/duckerry-daily-review SKILL.md v1.7.1
规则:只做待办里的事;按 批次 A→B→C→D 一次一批,每批完成即回报(改动文件+md5 / 自检 / 测试 / 备份路径),未获确认不跨批。
红线:改前全量备份到 /var/minis/shared/backup/DUCKERRY_pre_v523_20260926/;不改复盘/历史原始记录、不动归档、不删 *.bak*;不伪造数值。
熔断提示:开跑先执行 python3 scripts/state_digest.py --guard;若报 loops≥15 而本任务实际步骤 ≤5(已知假熔断),先做批次 A 再继续,禁止据此中止或写 BUDGET BREAK。
环境:iSH 上测试每次只跑 1 类、前台、不重定向;重脚本加 DK_DISABLE_MCAL=1。
收尾:moc_index → arch_check(11/11 或 10/10)→ doc_sync_check --strict(rc=0);技能升版并同步仓库镜像、核对 md5。
先只回报:批次 A 的改动计划 + 备份结果,等我确认后再动手。