canvas.ts 不是存储契约。
关系存储层 (canvasRelationalStore.ts) 和 save-v2 校验门引用的是 flowgraph-v2.ts / flowgraph-v2-schema.ts,
其 NodeType 有 13 个(vs canvas.ts 6 个),NodeState 末位是 skipped(vs canvas.ts cached)。
KMC 产出 {script, asset, storyboard, video, audio}(5个),全部落在 KAP Gate A 13 枚举内 → 不 reject
| Phase | KMC canvas_type | KMC asset_type | KAP NodeType ∈ 枚举 | 对齐 |
|---|---|---|---|---|
| p01 | script | topic | ✅ | ✅ |
| p02 | script | outline | ✅ | ✅ |
| p03 | script | script_phase | ✅ | ✅ |
| p04 | asset | character | ✅ | ✅ |
| p05 | script | script_phase | ✅ | ⚠️ 死映射 |
| p06 | script | script_phase | ✅ | ✅ |
| p07 | asset | scene | ✅ | ✅ |
| p08 | asset | scene | ✅ | ✅ |
| p09 | storyboard | storyboard | ✅ | ✅ |
| p09b | script | script_phase | ✅ | ✅ |
| p10 | audio | voice | ✅ | ✅ |
| p10b | video | clip | ✅ | ✅ |
| p10c | audio | voice | ✅ | ✅ |
| p11 | video | video | ✅ | ✅ |
| p12 | video | clip | ✅ | ✅ |
| p13 | script | delivery | ✅ | ✅ |
| p14 | script | script_phase | ✅ | ✅ |
| p15 | 未定义 (fallback: asset/scene) | — | — | 🚨 不可见 |
p05:已从 PHASE_REGISTRY 链中移出(DIALOGUE-REFORM),但 canvas_sync 三张表仍保留 p05 条目 → 死映射(不影响功能,建议清理)
KMC 有完整的适配层主动满足 save-v2 Gate B(缺必填参 → HTTP 400):
_normalize_media_fields(L607):path/audio_path/video_path/turnaround_sheet → filePath| KAP 节点类型 | Gate B 必填 | KMC 对应产出 | 风险 |
|---|---|---|---|
audio | filePath, shot_id, engine, duration_sec | voice_clips 透传 | 🚨 源缺则 400 |
video | filePath, shot_id, engine, duration_sec, resolution | video_clips 透传 | 🚨 源缺则 400 |
asset | filePath, label, assetType | p04/p07/p08 全带 | ✅ |
storyboard | label, shot_id, shot_type, duration_sec | KMC 用 shot_intent 而非 shot_type | 🚨 字段名风险 |
script | label, description | label 必有 + description 兜底 | ✅ |
6 个 phantom(全部有意占位,Notion forward-declaration):p07.scene_blueprint、p07.scene_temporal_variants、p11.midframes、p12.foley_stems、p12.bgm_tracks
| Orphan | 产出处 | 后果 | 严重度 |
|---|---|---|---|
| p15.feedback-log | p15_feedback.py:300 | 整个跨集反思产出对画布不可见 | 🚨 |
| p07.images | filesystem-fallback 别名 | 与 scene_images 生成重复节点 | ⚠️ |
| p09.continuity_report | p09_shot_breakdown.py:1534 | dict 型,静默丢弃 | ⚠️ |
| p03.audit | p03_script_audit.py:637 | dict 型别名,丢弃 | ℹ️ |
| p10b.error | p10b 异常路径 | string 型,丢弃 | ℹ️ |
KMC 持久化的 link dict 极简:{id, source, target, branchId, dataType}
dataType 实际只取 2 个值:output(管线流)+ reference(引用边)ref-{ref_type}-{src}-{tgt}| 维度 | KAP 侧事实 | 与 KMC 对齐? |
|---|---|---|
| canvas_links 表列 | 无 link_type / ref_type / semantic 列 | ⚠️ 巧合"对齐"(都丢) |
| LinkSemanticType | 仅 canvas.ts 有;FlowLinkV2 无此字段 → save 即丢 | 🚨 双向无持久化 |
| LinkRefType | 同上,仅 canvas.ts;FlowLinkV2 无 → 丢弃 | 🚨 |
| LinkDataType | FlowLinkV2Schema.dataType 为自由 string,不校验 | 🚨 词表零交集 |
KMC 实际写入 {success, pending, error, idle}(4值),全在 KAP Gate A 6 枚举内 → 不 reject
| KMC 写入的 state | 条件 | 依据 |
|---|---|---|
success | 无 error 且非 gate-awaiting | L1628 |
pending | gate awaiting_review | L1626 |
error | result["error"] 存在(优先于 pending) | L1623-1624 |
idle | 未选中的候选 scene/shot 子节点 | L3649,3732 |
KMC 从不写 running(无瞬态);KAP 的 cached(canvas.ts) vs skipped(flowgraph-v2) 自相矛盾
node_data["data"]["reviewStatus"](嵌套,L1684),
而 KAP 契约/存储读顶层 reviewStatus(flowgraph-v2-schema.ts:42)→
canvas_nodes.review_status 列恒 NULL → 审核徽章/过滤完全失效。
值本身没丢(活在 data JSON blob 里),但任何按顶层 reviewStatus 过滤的前端都看不到。
✅ runner 异常处理器在 re-raise 之前先 sync error stub(runner.py:2524,2587,2813),canvas_sync 见 error → state=error + 错误 tag 拼进 description → error/timeout 能正确反映为画布 error 节点
C1. P15_feedback 整相产出对画布不可见
runner 会跑 p15,但 canvas_sync 四张表无 p15 → feedback-log(含 rejected_phases/rejection_events/lesson_count)完全不落画布。
建议:三张表补 p15 条目;_PHASE_OUTPUT_MAP 增 "p15": [("feedback-log","跨集反思","script",True)]
C2. Link 的 ref/semantic 粒度全链路丢失
KMC 11 种 ref_type + KAP LinkSemanticType/LinkRefType 双向都无持久化。canvas_links 无列、FlowLinkV2 无字段、save 即丢。
建议:(a) KAP 加 link_type/ref_type 列并在 FlowLinkV2 建模;或 (b) 约定前端解析 id 前缀 ref-{type}-
C3. ReviewStatus 字段错位(嵌套 vs 顶层)
KMC 写 data.reviewStatus(嵌套 L1684),KAP 读顶层 reviewStatus → review_status 列恒 NULL。
建议:KMC 在 _build_phase_node / _build_gate_node 额外写顶层 node_data["reviewStatus"]
C4. Gate B 整批 400 风险
任一 audio/video/storyboard 节点缺必填即整张图 400。媒体守卫只救"缺 filePath",救不了"有 filePath 缺 engine/duration_sec/resolution/shot_type"。
建议:_build_artifact_node 增字段名归一化(shot_intent→shot_type 等)+ 缺关键字段的媒体节点统一降级为 script
| # | 问题 | 建议 |
|---|---|---|
| W1 | KAP 三套类型定义不同步,canvas.ts 过期(6 NodeType vs 13;cached vs skipped) | 统一以 flowgraph-v2 为唯一源,对齐/删除 canvas.ts |
| W2 | dataType 词表不交(output/reference vs text/image/video/audio/data) | 明确 output/reference 的前端处理,或 KMC 改用 KAP 词表 |
| W3 | p07.images orphan 产生重复节点 | 把 images 纳入 p07 声明集或在 fallback 抑制别名 |
| W4 | p09.continuity_report 静默丢弃 | 补 _PHASE_OUTPUT_MAP 声明 |
| W5 | FlowGraphNode 多字段持久化丢失(progress/groupId/routingDecision/variantIndex) | 确认是否仍需,否则从 canvas.ts 移除 |
| W6 | 微门 phaseIndex 共享致排序歧义(p10b/p10c 都=10) | 微门给唯一 phaseIndex 或显式 sort key |
_link_internal_references(L2381-2430)定义但无调用方 → 死代码| 项 | KMC(产出方) | KAP(消费/校验方) |
|---|---|---|
| phase 列表 | PHASE_REGISTRY 17 项(含 p15、不含 p05) | 无独立枚举;靠 node.phaseIndex/phaseName |
| 节点 type | {script, asset, storyboard, video, audio} | Gate A 枚举 13 个 |
| 节点 state | {success, pending, error, idle} | Gate A 枚举 6 个;canvas.ts 末位 cached(矛盾) |
| reviewStatus | 写在 data.reviewStatus(嵌套) | 读顶层 reviewStatus → review_status 列 |
| 边 dataType | {output, reference} | LinkDataType {text,image,video,audio,data}(不校验) |
| 边 ref/semantic | 11 种 ref_type,仅编码在 link id 串 | LinkSemanticType/LinkRefType 仅在 canvas.ts,无列、无字段、save 即丢 |
| 必填参校验 | 主动适配(normalize/passthrough/降级/description 兜底) | Gate B:缺必填 → 整图 400 |
/tmp/canvas-state-compare-report.md