现状 / 根因(review G7,PR #49 / #50 内置审发现)
config 序列化 wire 契约是非闭环 funnel:
- 上游(Medium,已锁):
src-tauri/src/config/model.rs 的 serde golden 测试 + src-tauri/src/model.rs 的 WebhookTunnelMode wire 值 golden(断言 camelCase 键存在 / snake 缺席 / 枚举序列化成 "quick"/"command"/"listener")——锁住 Rust 侧产出。
- 下游(Soft,开口):
src/config/types.ts 的 AppConfig interface + WebhookTunnelMode literal union 是手维护镜像,无机器校验。Rust 端改字段名 / 枚举增变体时,TS 侧不会自动失败。
WebhookTunnelMode 是多变体枚举(vs sourceKind/engineKind 单变体),下游漂移风险比既有字段更高,故显式立项。
这条 funnel 正是 .claude/rules/prmonitor/ai-robust.md 的「评级范例(acceptance)」所述同款 config Rust↔TS 契约,其「进一步 Hard 路径(future)」即本 issue。
已落地的局部缓解(本 PR #49 内)
G9 已把 TS 内部的双写单源化:WebhookTunnelMode union 由 WEBHOOK_TUNNEL_MODES as const 数组派生,fields.ts 的 options 复用之(Hard,TS 内 options↔union 不再漂移)。但 Rust↔TS 跨端那段下游仍是手维护(Soft)。
修复方向(Hard 化)
从 config/model.rs(+ model.rs 的相关枚举)codegen 派生 src/config/types.ts,CI 跑 git diff --exit-code 校验未手改 → Rust↔TS 漂移在 CI 不可表达地失败(Hard,对标章程载体决策原则 #1)。
低成本过渡(Medium):在 fields.test.ts 加 vitest 断言,锁 webhookTunnelMode 的 options 集合 == 期望三值,至少让 TS 侧值集有机器守护。
关联
现状 / 根因(review G7,PR #49 / #50 内置审发现)
config 序列化 wire 契约是非闭环 funnel:
src-tauri/src/config/model.rs的 serde golden 测试 +src-tauri/src/model.rs的WebhookTunnelModewire 值 golden(断言 camelCase 键存在 / snake 缺席 / 枚举序列化成"quick"/"command"/"listener")——锁住 Rust 侧产出。src/config/types.ts的AppConfiginterface +WebhookTunnelModeliteral union 是手维护镜像,无机器校验。Rust 端改字段名 / 枚举增变体时,TS 侧不会自动失败。WebhookTunnelMode是多变体枚举(vssourceKind/engineKind单变体),下游漂移风险比既有字段更高,故显式立项。已落地的局部缓解(本 PR #49 内)
G9 已把 TS 内部的双写单源化:
WebhookTunnelModeunion 由WEBHOOK_TUNNEL_MODES as const数组派生,fields.ts的options复用之(Hard,TS 内 options↔union 不再漂移)。但 Rust↔TS 跨端那段下游仍是手维护(Soft)。修复方向(Hard 化)
从
config/model.rs(+model.rs的相关枚举)codegen 派生src/config/types.ts,CI 跑git diff --exit-code校验未手改 → Rust↔TS 漂移在 CI 不可表达地失败(Hard,对标章程载体决策原则 #1)。低成本过渡(Medium):在
fields.test.ts加 vitest 断言,锁webhookTunnelMode的 options 集合 == 期望三值,至少让 TS 侧值集有机器守护。关联