素材工房 · 后端交接
对着 handoff §23.18–§23.20 的最终结论,把两个成片链路的 bug 修了, 并把"消化闭环 + 建 Agent 模型 + 检索字段合并"三件事落地。三个 commit,一条迁移,只上了 test/st 库。
图例 已实现并自测 待别人决定 / 待做
Part 1 · commit 5051eb1
现象:用户要 30s 多段成片,实际只拿到 1 段 15s,而且全程无报错——delivery 任务状态还是 done。
根因:src/lib/delivery-creative-payload.ts 的 pickDeliveryHandoff 走一份写死的白名单 DELIVERY_HANDOFF_KEYS。segments / target_duration_seconds / segment_count / segment_plan 等 19 个新契约字段从没进过白名单,转发给下游时被静默丢掉。下游 st2_delivery"只信机器可读字段、不从文字猜",拿到残缺数据判成非长表单,只出 1 段。
修法:delivery_handoff 是 st2_creative 写给 st2_delivery 的机器契约,Material Board 只是中继、不该按白名单把关。改成整对象透传(深拷贝),只对我们自己拥有 shape 的大对象(creative_unit / *_refs / gameplay_*)保留裁剪。
// 原:每个 key 过静态白名单,新字段永远漏 - if (!DELIVERY_HANDOFF_KEYS.has(key)) continue // 新:全字段透传,只裁剪已知大对象 + const cloned = pickAllowedMetaValue(key, child) // 未知 key → 深拷贝
自测:用真实 handoff 样本跑 bundle,24→22 字段(丢的 2 个是空数组 refs,本就该丢),segments(3 段)/ target_duration_seconds(30)/ segment_count(3) 全部保留。
根因:那条失败任务是 delivery run。任务中心/创意过程的重试按钮对失败 delivery 传的是 delivery run 自己的 id,但 retry-priority 端点的查询写死 ar.stage = 'creative' → 查不到 → 报错。端点本身已经支持"创意成功、成片失败"这个场景(has_failed_delivery),只是它要的是 creative run id。
修法:进事务先解析一次——delivery run id 顺 board.source_run_id 回它的 creative run;creative id 原样透传,其它/垃圾 id 仍走干净的 404。之后逻辑不变:重跑创意链,cron 自动接一条新成片。
// 失败 delivery dd32ba80 → 它的板 bdbbe31b → 源创意 run a7dc6802 SELECT CASE WHEN r.stage='delivery' THEN cb.source_run_id ELSE r.id END AS creative_run_id ...
自测:对 test 库跑解析,dd32ba80(delivery)→ a7dc6802(creative)✓,creative id → 自身 ✓。
Part 2 · commit 57fd35b · §23.19 / §23.20
PM 反馈消化引擎有两个配套的取数缺口——一个是"记不记录",一个是"记录了但没传给判断逻辑"。
digestGuidanceForAgent() 拉信号时原本过滤了 note IS NOT NULL,把所有没打字的点赞/点踩/加推(不分热点/成片)全挡在消化材料外。改成不在取数层过滤:全部纳入,权重交给判断逻辑——prompt 里把"仅操作、未附文字"标为弱信号,反映倾向但不单凭它改规则,量大的纯点击不稀释真正的文字反馈。
原查询只带 stage(哪个 tab),丢了"针对哪一条具体内容"。补上 ref_item_id/item_id + join 出标题 + 该内容的 source_run_id(追溯到产出它的具体任务)。prompt 用 《标题》+任务号 标注每条反馈是"针对某一条具体内容"还是"针对整体/流程",让消化能定向优化对应环节。
// prompt 里每条反馈/信号现在带对象标签
1. 【成片·《甜怖一秒反转》·任务fd4cd855】加推 —— (仅操作、未附文字 —— 弱信号)
2. 【整体/流程】[创意方案] 物理逻辑错了很多,镜头没按 board 来
自测:对真实 agent 跑新查询,无备注 boost 已纳入、标题 + source_run_id 正确 join(hot 素材无 source_run_id 时 COALESCE 兜住)。
Part 3 · commit 57fd35b · 待决2
隐患:POST /crawl/slots 没指定 Kit 时,直接把系统默认单元的同一行 id 写进 crawl_slots.creative_unit_id。所有用默认包的 Agent 共用同一条 creative_units 记录 → 一个 Agent 的消化改 steer_text 会串到别人。
根治(PM 定的方向,比消化时机 A/B/C 更彻底):建 Agent 时复制一份私有单元(字段 + creative_unit_refs 到新行),从创建那刻起就独立。visibility=private / auto_gen=true(不进 Kit 选择器,是绑给本 Agent 的副本、不是可复用资产包)。
自测:rollback 事务里确认产出 private / 非默认 / auto_gen 的私有副本。
Part 4 · commit ebb1582 · 待决1 = F1 + F2 · 迁移 0033
0027 当初把检索拆成 search_goal(用户手改)+ search_guidance(AI 改),PM 拍板合回单一「检索文档」(用户可编辑 + 保存 AI 润色 + 定时消化优化)。
| 概念 | 落到哪 | 动作 |
|---|---|---|
| 单一检索文档 | 复用 search_guidance 列 | search_goal 弃用,0033 backfill 并入 |
| title(Agent 名) | 复用 display_name 列 | 本就是 AI 生成、稳定、可改名,与 §23.1 对 title 定义吻合,不加冗余列 |
| 迁移 0033 | 只做数据 backfill | 加法、幂等、仅 test/st 库 |
GET /guidance 新增 title / search_doc;旧键(display_name/search_goal/search_guidance)保留并同步指向合并值,老 pm-loop demo 不断线。PATCH /guidance 收 search_doc + title(search_goal 作 legacy 别名 → 写检索文档),落 manual 版本(全文快照)。[目标] 前缀,直接发检索文档(cron + 手动再找一批两处)。display_name、检索浮层读合并文档。新增 polishSearchDoc()(cron.ts export):保存检索文档后在 PATCH 内跑一次 AI 润色改写,以用户文本为准只做语言梳理,返回润色后文本 + polished 标记。best-effort:key 缺失 / 失败 / 超时则保留用户原文,绝不丢内容;在事务外调用不占 DB 锁。
自测:0033 已应用且幂等(backfill 1 行,重跑 0);PATCH 的 UPDATE + 版本 INSERT(动态 changed 字面量 + jsonb 快照)在 rollback 事务跑通;老前端 PATCH search_goal 走别名仍写合并文档。typecheck + wrangler dry-run 全过。
Part 5
这几条我没自作主张,要产品/前端/DBA 拍:
0026–0033 全部只在 test/st 库(ep-noisy-wave),没上 prod。这套 guidance / 产品隔离 / 合字段的表结构上 prod 前,prod 站点用不了。
steer_text,消化仍会互相串。要彻底消除得写个一次性脚本给存量也 fork。
GET/PATCH 形状接:title / search_doc / 返回里的 polished 标记。
/api/delivery/:id/retry 的活,可另说。
display_name 的语义(AI 生成、稳定、显式改名)与 §23.1 对 title 的定义逐字吻合,就没加冗余的 title 列。若坚持要独立列,再加一条迁移即可。
附录
| commit | 做了什么 | 主要文件 |
|---|---|---|
5051eb1 | 成片链路两 bug | delivery-creative-payload.ts · v7.ts |
57fd35b | §23.19/20 消化 + 待决2 fork | cron.ts · api.ts |
ebb1582 | F1 合字段 + F2 润色 | cron.ts · guidance.ts · v7.ts · campaign-detail-page.tsx · migrations/0033 |
三个 commit 已推 st/test,CI 自动部署 sozai-st。验证入口:
GET /guidance 的 versions[] 是否按对象定向更新。GET /guidance 返回 title/search_doc;PATCH 存检索文档后返回 polished:true + 润色文本。