fix(w05): 两颗料不能是同一颗 —— 起单这一刻立墙,因为路只在这里

用户:「创建活动的启动参数里面不应该能选到同样的两个芯片」。
查下来这不只是没意义,是**把单子做死**:sub_eval.part 的主键是 eval_ref+internal_pn
(role 不在主键里),S1 配方铸的两行撞成同一个主键、后一笔覆盖前一笔,两行收成一行 ——
sub_eval_part_exists_status_found = 2 永不成立,S1 收不了步,而件上那两行人加不出来
(行源 mine:,没有「+加一行」),唯一出路是终止重开。与「两格留空」是同一条链。

平台加互斥声明 x-distinct(契约 distinctGroup)——与 x-link 正相反:那个是引导,这个是墙。
· 前端:别的格占着的候选这一格不列(自己填着的那个永远留着,否则 select 当场变空白),
  并说清是谁占了哪个;走「新增」自己写一个同样的 → 小红字 + 启动按不下去;
· 服务端 validateLaunchParams 独立拦(脚本 / API 绕不过),400 点名后填的那格;
· 「算不算同一个」= 去空白 + 不分大小写(launchDistinctKey,前后端同一把尺)——
  只挡精确相等的话 lm2596s-5.0 照样进去,混一颗垃圾主数据出来。
W05 两格挂 x-distinct: 'part',2.14.0 已装库核过。

测:服务端 6 条 + 前端 8 条(含联动与互斥合起来的真形状)+ 包内 1 条,三处变异验证过;
四道门禁绿(2548 测)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
xcs
2026-08-31 22:03:56 +08:00
co-authored by Claude Fable 5
parent 8c5f3a7736
commit e47ce92702
11 changed files with 331 additions and 30 deletions
+27
View File
@@ -200,9 +200,36 @@ export const launchParamSchema = z.object({
* 服务端**不据此立墙** —— combo 本就收候选之外的值,类型一致性归活动自己的收步判据管。
*/
linkGroup: z.string().optional(),
/**
* **互斥组名**(清单 `x-distinct`,2026-08-31 用户定)—— 同一组的几格**不能填同一个值**:
* 别的格已经占了的候选**不列**在这一格里(前端),自己写进来也拒(服务端 `validateLaunchParams`)。
*
* 与 `linkGroup` 是两件事,别混:那个是引导(收窄候选,填了别的照收),**这个是墙**。
* W05 两格填同一颗料会把单子做死 —— `sub_eval.part` 的主键是 `eval_ref + internal_pn`,
* 配方铸的两行撞成同一个主键,后一笔覆盖前一笔,两行收成一行:`sub_eval_part_exists_status_found = 2`
* 永不成立、S1 收不了步,而件上那两行人加不出来(行源是 `mine:sub_eval.part`,没有「+加一行」)——
* 唯一出路是终止重开。**墙立在起单这一刻,是因为路只在这里**:那时改一格就好了。
*
* 只管**标量格**(text / select / combo);数组格声明了也不算 —— 本期没有这种形状,真要了再补。
*/
distinctGroup: z.string().optional(),
});
export type LaunchParam = z.infer<typeof launchParamSchema>;
/**
* 「算不算同一个」的归一:去空白 + 不分大小写 —— **前后端同一把尺**。
* 大小写要归:料号这类身份不因字母大小写而不同,只挡精确相等的话,`lm2596s-5.0` 会照样进去,
* 混一颗垃圾主数据出来,人还得到一份自己跟自己比的评估。
*/
export function launchDistinctKey(value: string): string {
return value.trim().toLowerCase();
}
/** 撞上了那一格的话 —— 前端(填的当口)与服务端(400 的 detail)同一句,不许分叉 */
export function launchDistinctMessage(otherLabel: string): string {
return `与「${otherLabel}」填的是同一个 —— 这两格不能一样,换一个再启动`;
}
export const launchParamsSchema = z.object({
activityId: z.string(),
version: z.string(),