飞书 Card 收敛式重构 · 执行与修复复盘
飞书 card 渲染完成收敛式重构:原生 table 替代脆弱 column_set、长说明用 collapsible_panel 折叠、路由按内容分类分流。执行中途主力模型因额度不足触发 fallback,降级模型静默改歪一处路由分流维度,经 git stash 加备份双重 diff 审计定位,三处定点修复收口,全量测试 229 passed。唯一未收口项是折叠阈值修复尚未进运行态,需重启 gateway 后确认。
重启 gateway,用真实 agent 回复验证运行态折叠生效(约 1-2 分钟中断)。
全量测试 test_feishu.py + test_feishu_long_decision_autopublish.py:229 passed。
先把已验证方案当成稳定基线:保留当前 schedule / deliver / workdir,不急着继续扩面;新增候选先读源码、看 output、做 run-now 验证,再决定是否转 script-only。
证据摘要
- 全量测试
test_feishu.py+test_feishu_long_decision_autopublish.py:229 passed。 - 运行态脚本验证(真实路由
_build_outbound_payload):结构化内容判定 interactive ✓、原生 table 真实生成 ✓、折叠面板真实触发 ✓。 - 真实发送飞书 Home 频道 code=0 success。
行动清单
feishu-card skill 的 builder 约定与 schema 2.0 边界清单。边界 / 风险
折叠阈值(220→120)是 22:50 重启之后才改的,gateway 进程内存里跑的还是旧阈值。磁盘代码已验证,但 gateway agent 回复链路的真实折叠行为还需一次重启才能确认。这是当前唯一未收口项。
硬编码阈值对中文场景脆弱:中文长段落不换行导致行数判据失效,字符阈值差 1 个字就漏判。后续若调整折叠/分页阈值,必须同时考虑中文不换行特性,优先用字符数而非行数作主判据。
本次是飞书 card,但任何长任务执行中途 fallback 都可能发生类似偏差。已确认 fallback notify 功能(fallback.notify_on_activation)可让降级即时可见,建议长改造任务开启,降低静默偏差风险。
完整记录
飞书 Card 收敛式重构 · 执行与修复复盘(2026-06-15)
结论
飞书 card 渲染完成收敛式重构:原生 table 替代脆弱 column_set、长说明用 collapsible_panel 折叠、路由按内容分类分流。执行中途主力模型因额度不足触发 fallback,降级模型静默改歪一处路由分流维度,经 git stash 加备份双重 diff 审计定位,三处定点修复收口,全量测试 229 passed。唯一未收口项是折叠阈值修复尚未进运行态,需重启 gateway 后确认。
背景
涛哥反馈飞书 card 样式长期有瑕疵:显示效果不稳定、内容经常被截断显示不全。历史上经历过约 20 轮 text→post→interactive 的反复横跳,根因不是样式参数,而是架构问题:分类器 kind 过多互相打架、单卡 builder 不分页、没用飞书原生折叠能力。
改了什么
三个文件的收敛式改造(相对 HEAD:feishu.py +7 行,feishu_cards.py 大改 216 行,test_feishu.py +2 行):
- builder 收敛:report/table 两条 builder 并成一条主链
_compile_card_blocks_to_elements,消除重复逻辑。 - 原生 table 替代 column_set:markdown 表格改用飞书原生
table组件(data_type: markdown),移动端竖排友好,替掉脆弱的 column_set 斑马纹。 - 折叠面板:长纯文字 section 用
collapsible_panel承载,不再粗暴裁切成"已保留核心段落"。 - 路由按分类分流:结构化内容默认走 interactive 主链;带格式的简短聊天走 post;不再在 text/post/interactive 间乱跳。
Fallback 插曲(本次最有价值的经验)
执行中途主力模型 MC-4.8 因额度不足触发 HTTP 403,自动 fallback 到降级模型。降级模型在收敛路由时,把 post/card 的分流维度从"内容分类"误改成了"是否单行"("\n" not in content),导致多行的带格式短聊天被错误推向卡片渲染路径。
这是一个隐蔽的偏差:代码能跑、能过编译,但设计意图被悄悄改写。教训是——模型中途 fallback 后,绝不能信任"记忆里的完成态",必须对磁盘真实代码做差异审计。
审计方法
用两套基线做交叉验证:
- git stash 退回基线:把工作区 stash 回动手前状态,跑测试确认那两个失败测试在 HEAD 就是红的,证明不是本次改坏的。
- 备份 diff 比对:拿
before-convergent-refactor备份逐文件 diff,确认 builder 层重构干净无污染,fallback 真正改歪的只有 feishu.py 路由一处。
结论清晰:问题仅此一处,三行定点修复即可收口,无需推翻重写。
修复的三个问题
- 路由分流维度:改回按分类区分。结构化报告(report_structured 等)一律 interactive,chat_structured 才考虑 post。
- 分类器缺陷:
chat_structured把"结论+多列表的状态型回复"和"短富文本闲聊"混成一个 kind,期望出口却相反。新增规则:带 ≥2 个无序列表项且无代码块 → 归入 report_structured → 走 interactive。 - 折叠阈值脆弱性:原阈值
字符>220 或 行数>=3。那段"根因复盘"正文好 219 字,差 1 字符没触发折叠;更深的问题是中文长段落往不换行(行数=1),行数判据几乎永远失效,等于折叠只剩一根高阈值独木桥。改成字符>120 或 行数>=4。
飞书 Card Schema 2.0 边界(技术沉淀)
live 实测确认的硬约束,供后续避坑:
collapsible_panel不能内嵌table,表格必须放body.elements顶层。column_set+background_color在 schema 2.0 下直接 HTTP 400,已废弃该路径。- 原生
table单卡最多 5 个,单元格内容超长末尾省略(光标悬浮查看)。 collapsible_panel需飞书客户端 7.20+,schema 2.0 已默认满足。
验证结果
- 全量测试
test_feishu.py+test_feishu_long_decision_autopublish.py:229 passed。 - 运行态脚本验证(真实路由
_build_outbound_payload):结构化内容判定 interactive ✓、原生 table 真实生成 ✓、折叠面板真实触发 ✓。 - 真实发送飞书 Home 频道 code=0 success。
风险与边界
风险 1:折叠阈值修复尚未进运行态
折叠阈值(220→120)是 22:50 重启之后才改的,gateway 进程内存里跑的还是旧阈值。磁盘代码已验证,但 gateway agent 回复链路的真实折叠行为还需一次重启才能确认。这是当前唯一未收口项。
风险 2:阈值类判据的中文特性
硬编码阈值对中文场景脆弱:中文长段落不换行导致行数判据失效,字符阈值差 1 个字就漏判。后续若调整折叠/分页阈值,必须同时考虑中文不换行特性,优先用字符数而非行数作主判据。
风险 3:fallback 静默改歪的系统性隐患
本次是飞书 card,但任何长任务执行中途 fallback 都可能发生类似偏差。已确认 fallback notify 功能(fallback.notify_on_activation)可让降级即时可见,建议长改造任务开启,降低静默偏差风险。
下一步
- 重启 gateway,用真实 agent 回复验证运行态折叠生效(约 1-2 分钟中断)。
- 运行态确认后,将本次收敛重构固化进
feishu-cardskill 的 builder 约定与 schema 2.0 边界清单。