Archived
fix(w05): 复核轮审核人说了算,并把这一轮改了什么说进对话区
用户第二次实测:「重做还是没有修改掉内容」—— 他写「静态电流结论改成不匹配」,而两颗料的 静态电流都是 5mA,AI 搬出第一轮那份规矩里的第 3 条(硬约束不因措辞变成 match)把他顶了回去: evidence_note 白纸黑字「维持上一轮 match…硬规矩要求按实际值判定,不能因措辞改变结论」。 **行的范围这次是对的**(只把那一条交给 AI、只写回那一条),错在**谁说了算**。三处想岔了: ① 那条规矩管的是它自己判的时候别被措辞带偏,不是用来否决审核人的; ② 方向也反了 —— 它守的是「不许把不满足说成满足」(危险方向),而他要的是收紧结论; ③ 更根本:审核人在件上本来就能亲手改任何一条四态,AI 在重判这条路上顶回去, 等于同一件事在两条路上给出相反的答案。 改:复核指令明写这条覆盖 —— 他点名要什么结论就落什么,不要顶回去;落的同时 evidence_note 记两句「按谁的意见」+「数据面是什么」,下一个人回看能一眼分清数据判的还是人定的。 同批(用户接着提:「需要把 ai 的修改意见通过右边 ai 聊天窗口展示出来,不然都不知道发生了什么」): 复核完在对话区说一句「按你的意见复核了 N 条 —— <参数名>:<判断依据>」,摆的是件上那一行 自己的话,不另编一句。**它必须排在卡之前** —— 发了卡这一拍就收了,排在卡后面的 say 要等 下一拍才跑:原来那句「差异结论已送审,请核对」实测正是在人答完之后才出现的;而且它与卡自己的 ask 本来就是同一件事,一并退役。 验收:e2e w05 5/5 released、被拒 0;案例 0 三条断言全绿 —— 「复核那一轮在对话区说了话」「打回点名要的结论真落下去了(使能阈值 = conditional)」 「打回只动了被点名的那几条」。包内 +2 测。W05@2.21.0 已装库。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
@@ -1834,6 +1834,29 @@
|
|||||||
.dossiers 三列网格(1fr·76px·1fr),中间列是实体动画道 —— ⇄ 徽呼吸 + 双点绕徽轨道
|
.dossiers 三列网格(1fr·76px·1fr),中间列是实体动画道 —— ⇄ 徽呼吸 + 双点绕徽轨道
|
||||||
对转(sw-orbit),总线虚线在道里连两卡;窄屏单列收道。浏览器两帧相位实证。
|
对转(sw-orbit),总线虚线在道里连两卡;窄屏单列收道。浏览器两帧相位实证。
|
||||||
|
|
||||||
|
- **复核轮审核人说了算 —— AI 不许拿硬规矩顶回去**(2026-09-01 用户第二次实测:「重做还是没有
|
||||||
|
修改掉内容」):他写「静态电流结论改成不匹配」,而两颗料的静态电流都是 5mA,AI 于是搬出
|
||||||
|
第一轮那份规矩里的第 3 条(硬约束不因措辞变成 match)把他顶了回去 ——
|
||||||
|
`evidence_note` 白纸黑字:「维持上一轮 match…硬规矩要求按实际值判定,不能因措辞改变结论」。
|
||||||
|
**行的范围这次是对的**(只把那一条交给 AI、只写回那一条,其余六条一个字没动),错在**谁说了算**。
|
||||||
|
两处想岔了:①那条规矩管的是**它自己判**的时候别被措辞带偏,不是用来否决审核人的;
|
||||||
|
②方向也反了 —— 那条守的是「不许把不满足说成满足」(危险方向),而他要的是**收紧**结论;
|
||||||
|
③更根本的是:审核人在件上**本来就能亲手改任何一条四态**,AI 在重判这条路上顶回去,
|
||||||
|
只是让同一件事在两条路上给出相反的答案。
|
||||||
|
改:复核指令明写这条覆盖 —— **他点名要什么结论就落什么**(「不匹配」= mismatch、「有条件」=
|
||||||
|
conditional…,不要跟他讲道理、不要顶回去);落的同时 `evidence_note` 记两句
|
||||||
|
「按谁的意见」+「数据面是什么」(例:「按审核人意见调整为 mismatch:<原话>。数据面:两侧均为 5mA。」)
|
||||||
|
—— 下一个人回看时要能一眼分清**这是数据判出来的**还是**这是人定的**;
|
||||||
|
他只是提疑问 / 要补依据的,照旧由 AI 复核后自判。
|
||||||
|
e2e 案例 0 的打回意见同批换成**点名要结论**那一种,新断言逐字核那一行真变成了他要的值
|
||||||
|
(「打回点名要的结论真落下去了(使能阈值.difference_status = conditional)」)。
|
||||||
|
**同批把这一轮的交代摆进对话区**(用户接着提:「需要把 ai 的修改意见通过右边 ai 聊天窗口
|
||||||
|
展示出来,不然都不知道发生了什么」):复核完说一句「按你的意见复核了 N 条 —— <参数名>:<判断依据>」,
|
||||||
|
摆的是**件上那一行自己的话**,不另编一句(对话区与件上说的是同一件事,就该是同一句话)。
|
||||||
|
**它必须排在卡之前** —— 发了卡这一拍就收了,排在卡后面的 `say` 要等下一拍才跑:
|
||||||
|
原来那句「差异结论已送审,请核对」实测正是在**人答完之后**才出现的,而且它与卡自己的 `ask`
|
||||||
|
本来就是同一件事,一并退役。
|
||||||
|
|
||||||
- **打不回的验收卡就别摆那颗钮**(2026-09-01 用户定:「评审放行与落账确认这一步的验收卡不应该
|
- **打不回的验收卡就别摆那颗钮**(2026-09-01 用户定:「评审放行与落账确认这一步的验收卡不应该
|
||||||
有重做的选项,因为这里都没有接入 ai」):W05 的 T_release 整个由配方跑完(`guide` 是空串,
|
有重做的选项,因为这里都没有接入 ai」):W05 的 T_release 整个由配方跑完(`guide` 是空串,
|
||||||
不问模型),件又是只读的 —— 打回之后**没有任何东西能接住那句意见**:配方只会原样再提交一次,
|
不问模型),件又是只读的 —— 打回之后**没有任何东西能接住那句意见**:配方只会原样再提交一次,
|
||||||
|
|||||||
@@ -406,8 +406,8 @@ describe('S3 / S4 配方', () => {
|
|||||||
const s4 = stepOf('T_release')?.auto?.do ?? [];
|
const s4 = stepOf('T_release')?.auto?.do ?? [];
|
||||||
const s2 = stepOf('S2_assess')?.auto?.do ?? [];
|
const s2 = stepOf('S2_assess')?.auto?.do ?? [];
|
||||||
|
|
||||||
it('S3 九笔:圈范围 → 兜底扩范围 → 复核重判 → 落明细 → 明细重算 → 关系 → 验证记录 → 卡 → 交代', () => {
|
it('S3 九笔:圈范围 → 兜底扩范围 → 复核重判 → 落明细 → 明细重算 → 关系 → 验证记录 → 交代 → 卡', () => {
|
||||||
expect(s3.map((a) => a.kind)).toEqual(['project', 'project', 'analyze', 'project', 'project', 'project', 'project', 'card', 'say']);
|
expect(s3.map((a) => a.kind)).toEqual(['project', 'project', 'analyze', 'project', 'project', 'project', 'project', 'say', 'card']);
|
||||||
for (const at of [0, 1, 3, 4]) expect(s3[at]?.kind === 'project' && s3[at].into).toBe('substitution.difference_item');
|
for (const at of [0, 1, 3, 4]) expect(s3[at]?.kind === 'project' && s3[at].into).toBe('substitution.difference_item');
|
||||||
expect(s3[5]?.kind === 'project' && s3[5].into).toBe('substitution.relation');
|
expect(s3[5]?.kind === 'project' && s3[5].into).toBe('substitution.relation');
|
||||||
expect(s3[6]?.kind === 'project' && s3[6].into).toBe('validation.record');
|
expect(s3[6]?.kind === 'project' && s3[6].into).toBe('validation.record');
|
||||||
@@ -457,6 +457,19 @@ describe('S3 / S4 配方', () => {
|
|||||||
/* 判法一处真源:复核指令以第一轮那份规矩打头,后面才接复核纪律 */
|
/* 判法一处真源:复核指令以第一轮那份规矩打头,后面才接复核纪律 */
|
||||||
const rules = s2[0]?.kind === 'analyze' ? s2[0].instruction : '';
|
const rules = s2[0]?.kind === 'analyze' ? s2[0].instruction : '';
|
||||||
expect(redo?.kind === 'analyze' && redo.instruction.startsWith(rules)).toBe(true);
|
expect(redo?.kind === 'analyze' && redo.instruction.startsWith(rules)).toBe(true);
|
||||||
|
/*
|
||||||
|
* **复核轮审核人说了算**(2026-09-01 用户第二次实测:「重做还是没有修改掉内容」)——
|
||||||
|
* 他写「静态电流结论改成不匹配」,而两颗料的静态电流都是 5mA,AI 搬出第一轮那条
|
||||||
|
* 「硬约束不因措辞变成 match」把他顶了回去。那条规矩管的是**它自己判**的时候别被措辞带偏;
|
||||||
|
* 审核人是这一步的责任人(要签他的字,他在件上本来就能亲手改任何一条四态),不归它管。
|
||||||
|
* 指令里必须**明写这条覆盖**,否则前面那份规矩排在前面、模型照旧照它办。
|
||||||
|
*/
|
||||||
|
const tail = redo?.kind === 'analyze' ? redo.instruction.slice(rules.length) : '';
|
||||||
|
expect(tail).toContain('这一轮不归它管');
|
||||||
|
expect(tail).toContain('他点名要什么结论,就落什么');
|
||||||
|
expect(tail).toContain('不要顶回去');
|
||||||
|
/* 落的同时要把「按谁的意见、数据面是什么」记进依据 —— 下一个人得能分清人定的与数据判的 */
|
||||||
|
expect(tail).toContain('数据面');
|
||||||
/* 入参:上一轮结论 + 他写的意见 —— 少了任何一样,重判要么无据可依,要么读不到意见 */
|
/* 入参:上一轮结论 + 他写的意见 —— 少了任何一样,重判要么无据可依,要么读不到意见 */
|
||||||
const fields: Readonly<Record<string, unknown>> = redo?.kind === 'analyze' ? redo.input.fields : {};
|
const fields: Readonly<Record<string, unknown>> = redo?.kind === 'analyze' ? redo.input.fields : {};
|
||||||
for (const key of ['last_status', 'last_impact', 'last_evidence', 'last_unknown_disposition', 'reviewer_note']) {
|
for (const key of ['last_status', 'last_impact', 'last_evidence', 'last_unknown_disposition', 'reviewer_note']) {
|
||||||
@@ -549,8 +562,31 @@ describe('S3 / S4 配方', () => {
|
|||||||
expect(stepOf('S3_review')?.auto?.let).toBe(stepOf('S2_assess')?.auto?.let);
|
expect(stepOf('S3_review')?.auto?.let).toBe(stepOf('S2_assess')?.auto?.let);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* **交代必须排在卡之前**(2026-09-01 用户:「需要把 ai 的修改意见通过右边 ai 聊天窗口展示出来,
|
||||||
|
* 不然都不知道发生了什么」)—— 发了卡这一拍就收了,排在卡后面的 `say` 要等**下一拍**才跑,
|
||||||
|
* 那时人早看完卡了。实测:原来那句「差异结论已送审,请核对」出现在人答完之后。
|
||||||
|
* 两句互斥:被打回那一轮说「按你的意见改了哪一条、改成什么」(摆的是件上那一行自己的
|
||||||
|
* `evidence_note`,不另编一句);第一轮说「结论已备好,请核对」。
|
||||||
|
*/
|
||||||
|
it('打回那一轮的交代排在卡之前,摆的是件上那一行的判断依据', () => {
|
||||||
|
const kinds = s3.map((a) => a.kind);
|
||||||
|
/* **排在卡之前**:发了卡这一拍就收了,排在后面的 say 要等下一拍 —— 那时人早看完卡了 */
|
||||||
|
expect(kinds.lastIndexOf('say')).toBeLessThan(kinds.indexOf('card'));
|
||||||
|
/* 只在被打回那一轮说 —— 第一轮那句与卡自己的 ask 是同一件事,退役了 */
|
||||||
|
const redoSay = s3[7];
|
||||||
|
expect(redoSay?.kind === 'say' && redoSay.when).toBe('case_redo_note != ""');
|
||||||
|
const text = redoSay?.kind === 'say' ? redoSay.text : undefined;
|
||||||
|
const parts = JSON.stringify(text);
|
||||||
|
expect(parts).toContain('按你的意见复核了');
|
||||||
|
/* 摆的是件上那一行自己的话与名字 —— 对话区与件上说的是同一件事,就该是同一句话 */
|
||||||
|
expect(parts).toContain('evidence_note');
|
||||||
|
expect(parts).toContain('parameter_name');
|
||||||
|
expect(parts).toContain('substitution_difference_item_redo_scope_named');
|
||||||
|
});
|
||||||
|
|
||||||
it('S3 的卡:审核面孔、单一选项、挂本步的件', () => {
|
it('S3 的卡:审核面孔、单一选项、挂本步的件', () => {
|
||||||
const card = s3[7];
|
const card = s3[8];
|
||||||
expect(card?.kind === 'card' && card.as).toBe('decide');
|
expect(card?.kind === 'card' && card.as).toBe('decide');
|
||||||
expect(card?.kind === 'card' && card.variant).toBe('review');
|
expect(card?.kind === 'card' && card.variant).toBe('review');
|
||||||
expect(card?.kind === 'card' ? card.options ?? [] : []).toHaveLength(1);
|
expect(card?.kind === 'card' ? card.options ?? [] : []).toHaveLength(1);
|
||||||
|
|||||||
@@ -487,10 +487,17 @@ const REVIEW_REDO_ANALYZE = {
|
|||||||
instruction: [
|
instruction: [
|
||||||
ASSESS_RULES,
|
ASSESS_RULES,
|
||||||
'',
|
'',
|
||||||
'【这一轮是复核】下面**只列了审核人这次点到的那几条**(他写的话在 reviewer_note,每条都带着上一轮的结论 last_*)。',
|
'【这一轮是复核,审核人说了算】下面**只列了他这次点到的那几条**(他写的话在 reviewer_note,每条都带着上一轮的结论 last_*)。',
|
||||||
'· 按他说的复核这几条:该改就改,并在 evidence_note 里写清这一轮改了什么、依据是什么;',
|
'',
|
||||||
'· 复核下来确实是上一轮判对了,就把 last_* 原样带回,evidence_note 说明为什么维持;',
|
'**上面第 3 条(硬约束不因措辞变成 match)管的是你自己判的时候别被措辞带偏;这一轮不归它管** ——',
|
||||||
'· 他要的若与硬规矩冲突(比如要把证据不足的硬约束判成 match),照硬规矩判,并在 evidence_note 里说明为什么不能照办;',
|
'审核人是这一步的责任人,这份结论要签他的字,而且他在界面上本来就能亲手改任何一条的四态。',
|
||||||
|
'',
|
||||||
|
'· **他点名要什么结论,就落什么**:「改成不匹配 / 不符」= mismatch,「一致 / 匹配」= match,',
|
||||||
|
' 「判不了 / 待确认」= unknown,「有条件 / 加验证后可用」= conditional。不要跟他讲道理、不要顶回去。',
|
||||||
|
'· 落的同时把实情记在 evidence_note 里,**一句按谁的意见、一句数据面是什么**,例如:',
|
||||||
|
' 「按审核人意见调整为 X:<他的原话>。数据面:原料 5mA / 候选 5mA,两侧一致。」',
|
||||||
|
' —— 下一个人回看时要能一眼分清「这是数据判出来的」还是「这是人定的」。',
|
||||||
|
'· 他只是提疑问、要补依据、要改写措辞(没点名要哪个结论):你复核后自己判,evidence_note 写清这一轮改了什么。',
|
||||||
'· **列出来的每一条都要回**,一条不多、一条不少。',
|
'· **列出来的每一条都要回**,一条不多、一条不少。',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
input: {
|
input: {
|
||||||
@@ -948,6 +955,39 @@ export const ASSESSMENT_STEPS = [
|
|||||||
这一步只重算判定(推荐等级跟着四态走),四格交给人,见 `RELATION_RECOMPUTE` 的头注。 */
|
这一步只重算判定(推荐等级跟着四态走),四格交给人,见 `RELATION_RECOMPUTE` 的头注。 */
|
||||||
RELATION_RECOMPUTE,
|
RELATION_RECOMPUTE,
|
||||||
VALIDATION_PROJECTION,
|
VALIDATION_PROJECTION,
|
||||||
|
/*
|
||||||
|
* **重判完要在对话区说清「按你的意见改了哪一条、改成什么」**(2026-09-01 用户:
|
||||||
|
* 「需要把 ai 的修改意见通过右边 ai 聊天窗口展示出来,不然都不知道发生了什么」)。
|
||||||
|
*
|
||||||
|
* **必须排在卡之前** —— 发了卡这一拍就收了,排在卡后面的笔要等下一拍才跑
|
||||||
|
* (那时人早就看完卡了,这句话就成了马后炮:原来那句「差异结论已送审,请核对」
|
||||||
|
* 实测正是在**人答完之后**才出现的)。
|
||||||
|
*
|
||||||
|
* 摆的是件上那一行自己的话(`evidence_note` —— 复核指令要求它写成
|
||||||
|
* 「按审核人意见调整为 X:<原话>。数据面:…」),不是另编一句:
|
||||||
|
* 对话区与件上说的是同一件事,就该是同一句话。
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
kind: 'say' as const,
|
||||||
|
when: 'case_redo_note != ""',
|
||||||
|
text: {
|
||||||
|
cat: [
|
||||||
|
'按你的意见复核了 ',
|
||||||
|
{ in: 'substitution_difference_item_redo_scope_named' },
|
||||||
|
' 条 —— ',
|
||||||
|
{ lookup: 'mine:substitution.difference_item', by: { redo_scope: 'named' }, take: 'parameter_name', else: '' },
|
||||||
|
':',
|
||||||
|
{ lookup: 'mine:substitution.difference_item', by: { redo_scope: 'named' }, take: 'evidence_note', else: '' },
|
||||||
|
' 件上那几行已经改好,再核一遍,没问题就点「确认通过」。',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
* ~~第一轮那句「差异结论已送审,请在件上逐条核对」~~(2026-09-01 退役):
|
||||||
|
* 它与卡自己的 `ask` 说的是同一件事(「逐条差异结论已备好。请在工作区的件上逐条核对…」)——
|
||||||
|
* 摆两遍是复读。而且它排在卡后面,要等下一拍才跑:实测那句话出现在**人答完之后**。
|
||||||
|
* 打回那一轮不同 —— 那时有新东西要交代(改了哪一条、改成什么),所以只留上面那一句。
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
kind: 'card' as const,
|
kind: 'card' as const,
|
||||||
as: 'decide' as const,
|
as: 'decide' as const,
|
||||||
@@ -961,7 +1001,8 @@ export const ASSESSMENT_STEPS = [
|
|||||||
{ k: '本轮结论', v: { lookup: 'mine:substitution.relation', by: {}, take: 'difference_summary', else: '' } },
|
{ k: '本轮结论', v: { lookup: 'mine:substitution.relation', by: {}, take: 'difference_summary', else: '' } },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ kind: 'say' as const, text: '差异结论已送审,请在件上逐条核对。' },
|
/* ~~卡后面那一句 `say`~~(2026-09-01 退役):发了卡这一拍就收了,它要等下一拍才跑 ——
|
||||||
|
实测「差异结论已送审,请在件上逐条核对」出现在**人答完之后**。两句交代都提到卡之前去了。 */
|
||||||
/* `] as const`:这个数组也引用了 RELATION_PROJECTION/VALIDATION_PROJECTION —— 理由同 S2 的 do 数组头上那条注释 */
|
/* `] as const`:这个数组也引用了 RELATION_PROJECTION/VALIDATION_PROJECTION —— 理由同 S2 的 do 数组头上那条注释 */
|
||||||
] as const,
|
] as const,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export const manifest: ActivityManifest = {
|
|||||||
activityId: ACTIVITY_ID,
|
activityId: ACTIVITY_ID,
|
||||||
name: 'ACT-WORK-05 · 差异评估',
|
name: 'ACT-WORK-05 · 差异评估',
|
||||||
/* 重写不是改 —— 同版重装是 no-op(静默丢失,踩过) */
|
/* 重写不是改 —— 同版重装是 no-op(静默丢失,踩过) */
|
||||||
packageVersion: '2.18.0',
|
packageVersion: '2.21.0',
|
||||||
category: '需求分析与方案匹配',
|
category: '需求分析与方案匹配',
|
||||||
sdkVersion: '0.1.0-m5',
|
sdkVersion: '0.1.0-m5',
|
||||||
checksum: 'dev-checksum-part-substitution-assessment',
|
checksum: 'dev-checksum-part-substitution-assessment',
|
||||||
|
|||||||
+32
-1
@@ -637,7 +637,20 @@ const SUITES = {
|
|||||||
sample: 0,
|
sample: 0,
|
||||||
name: '候选缺库 · XL2596S-5.0 建档并选已有类型(type_1,2026-08-31 起本活动只选不建)'
|
name: '候选缺库 · XL2596S-5.0 建档并选已有类型(type_1,2026-08-31 起本活动只选不建)'
|
||||||
+ '· 审核先点名意见驳回再通过',
|
+ '· 审核先点名意见驳回再通过',
|
||||||
decideSeq: ['custom:使能阈值那条 UNKNOWN 的去向请写明验证任务号与测试条件', 'approve'],
|
/*
|
||||||
|
* **点名要一个结论**(2026-09-01 用户第二次实测:「重做还是没有修改掉内容」——
|
||||||
|
* 他写「静态电流结论改成不匹配」,AI 搬出「硬约束不因措辞改判」把他顶了回去)。
|
||||||
|
* 审核人是这一步的责任人:他点名要什么结论就该落什么。这条意见既点了名(使能阈值)
|
||||||
|
* 又点了结论(conditional),`expectRedoSetsStatus` 收工时逐字核。
|
||||||
|
*/
|
||||||
|
decideSeq: ['custom:使能阈值那条不是判不了,改成 conditional(有条件)—— 补一次实测就能用', 'approve'],
|
||||||
|
expectRedoSetsStatus: { address: 'substitution.difference_item', nameCol: 'parameter_name', param: '使能阈值', column: 'difference_status', equals: 'conditional' },
|
||||||
|
/*
|
||||||
|
* 复核完得在对话区说清「按你的意见改了哪一条、改成什么」(2026-09-01 用户:
|
||||||
|
* 「需要把 ai 的修改意见通过右边 ai 聊天窗口展示出来,不然都不知道发生了什么」)。
|
||||||
|
* 那句话必须**排在卡之前**才赶得上人看卡 —— 排在卡后面的 say 要等下一拍才跑。
|
||||||
|
*/
|
||||||
|
expectRedoNarration: '按你的意见复核了',
|
||||||
expectDecision: true,
|
expectDecision: true,
|
||||||
expectPort: 'assessment-released',
|
expectPort: 'assessment-released',
|
||||||
/*
|
/*
|
||||||
@@ -1705,6 +1718,24 @@ async function runCase(suite, kase) {
|
|||||||
console.log(' ⚠️ 这一例没有要补的数据,却派出了一张数据工单 —— 判失败');
|
console.log(' ⚠️ 这一例没有要补的数据,却派出了一张数据工单 —— 判失败');
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
|
if (kase.expectRedoNarration !== undefined) {
|
||||||
|
const said = (last?.trail ?? []).some((e) => String(e.title ?? '').includes(kase.expectRedoNarration));
|
||||||
|
if (said) console.log(` 复核那一轮在对话区说了话(「${kase.expectRedoNarration}…」)`);
|
||||||
|
else {
|
||||||
|
console.log(` ⚠️ 复核完对话区一个字没说(找不到「${kase.expectRedoNarration}」)—— 人不知道发生了什么,判失败`);
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (kase.expectRedoSetsStatus !== undefined) {
|
||||||
|
const { address, nameCol, param, column, equals } = kase.expectRedoSetsStatus;
|
||||||
|
const row = (redoAfter ?? draftRows(last?.drafts ?? [], address)).find((r) => String(r[nameCol] ?? '') === param);
|
||||||
|
const got = String(row?.[column] ?? '');
|
||||||
|
if (got === equals) console.log(` 打回点名要的结论真落下去了(${param}.${column} = ${equals})`);
|
||||||
|
else {
|
||||||
|
console.log(` ⚠️ 打回点名要「${equals}」,${param}.${column} 却是「${got || '(没取到)'}」—— 判失败(AI 又把审核人顶回去了?)`);
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (kase.expectRedoTouchesOnlyNamed !== undefined) {
|
if (kase.expectRedoTouchesOnlyNamed !== undefined) {
|
||||||
/* `address` 在轮询那一头取快照时用过,这儿只比对已经存下来的两份 */
|
/* `address` 在轮询那一头取快照时用过,这儿只比对已经存下来的两份 */
|
||||||
const { nameCol, cols } = kase.expectRedoTouchesOnlyNamed;
|
const { nameCol, cols } = kase.expectRedoTouchesOnlyNamed;
|
||||||
|
|||||||
Reference in New Issue
Block a user