W05 收口:五例在收紧断言下全 released · 全被拒 0(活动 1.2.9 → 1.3.6)

第 7–12 轮逼出七条(T–Z),两条是脚本自己的、五条是活动的,其中一条上结构:
- W 参数名写成英文 key,与库里中文行不是同一行 → 27 条里 14 条 UNKNOWN。措辞两遍 +
  乘法对账都拦不住单颗料那一路(5 = 5×1 恒成立),改自指 refersTo:param_name
  只能用台账里已经在用的名字,一颗料时也咬得住。
- V/Z 数据工单那一项的两个方向:建完第一颗就收掉(再给第二颗发卡撞「已办完」)、
  铺完骨架就标 created 直接 finish(撞「从没发过卡」)—— 顺序写死:骨架 → 发卡 →
  拍结束 → 人交回 → 才标 created;absent 没清零不许 finish。
- T P-10 也要「发卡前骨架先有行」;X 第二颗缺库也要先问。
- 脚本:U 一例翻车不拖垮整套;Y 按闸的指示「加一行」;断言收紧 —— 点名的行整例跑完
  仍没出现 = 失败,决策卡按「问的是哪件事」数(第 9 轮逮到一次假绿)。

流程上两条纪律(用户当场纠正):只跑受影响的那一例,改了平台共享面才全跑;先说计划再动手。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJcX8A6TWp4GRs41TYryEh
This commit is contained in:
xcs
2026-08-27 11:13:53 +08:00
co-authored by Claude Fable 5
parent 182d3c39b5
commit 6f7513aa58
6 changed files with 188 additions and 14 deletions
+61 -1
View File
@@ -709,6 +709,8 @@ const SUITES = {
name: '三候选 · 两颗缺库各问一次 · 国产 32V 硬约束不推荐',
decideSeq: ['create', 'create', 'approve'],
expectDecision: true,
// 两颗候选缺库 → 按规格各问一次(审核卡也是决策卡,所以要按问法数,不能只看张数)
expectAsks: [{ re: /查无记录/, count: 2 }],
expectPort: 'assessment-released',
stageEdits: {
'parts.profile': [
@@ -906,6 +908,7 @@ async function answerDecisions(taskId, kase, answered) {
body: JSON.stringify({ reply: { k: 'decision', cardId: card.id, value: picked.value, note: custom ? want.slice(7) : '试跑代答' } }),
});
answered.add(card.id);
asked.push(String(card.ask ?? card.title ?? ''));
count += 1;
console.log(` 决策卡拍板:${card.ask?.slice(0, 40) ?? ''} → ${picked.label ?? picked.value}`);
}
@@ -966,10 +969,34 @@ function buildEdits(stage, drafts, kase = {}) {
if (!target) {
const wanted = allGiven ? keyCols.map((k) => keyVals[k]).join('/') : `待填第${i}行`;
const have = rows.map((r) => keyCols.map((k) => r[k]).join('/')).join(', ');
/*
* **点名的行找不到 = 判失败,不是提个醒**(2026-08-27 实测:模型把参数名写成英文 key
* `input_voltage_range`,而库里既有行是中文「输入电压范围」—— 参数名是主键的一半,
* 两套名字对不上,比对时 27 条里 14 条判成 UNKNOWN。而这一例照样报「1/1 通过」:
* 断言报的通过是假的,比断言报的失败是假的更糟 —— 后者还有人去查。)
*/
/*
* **件上没有这一行就「加一行」** —— 人在浏览器里就是这么做的(闸的原话:
* 「先在件上加一行填好再提交」),脚本从前只会填已有行,于是模型漏写骨架时
* 这一例直接卡死(2026-08-27:P-10 零行,连吃三次 400 抛出)。
* 主键齐了才加(凑不出钥匙的行基座也认不出),加完从「缺」的名单里划掉。
*/
if (allGiven) {
lines.push({ ...keyVals, ...cells });
missedRows.delete(`${keyCols.join('+')}=${wanted}`);
console.log(` 件上加一行(${keyCols.join('+')}=${wanted})—— 模型没铺这行骨架,照闸的指示补`);
continue;
}
missedRows.add(`${keyCols.join('+')}=${wanted}`);
console.log(` ⚠️ 找不到要填的行(${keyCols.join('+')}=${wanted});现有行:${have}`);
continue;
}
taken.add(sig(target));
/*
* **填上了就从「缺」的名单里划掉** —— 同一类卡一例里可能发好几张(两颗缺库各一张 P-08),
* 第一张上第二颗的行还不存在是**正常的**,不是缺;整例跑完仍没填上才是真缺。
*/
if (allGiven) missedRows.delete(`${keyCols.join('+')}=${keyCols.map((k) => keyVals[k]).join('/')}`);
lines.push({ ...keyOf(target), ...cells });
}
if (stage.fillMissing) {
@@ -1125,6 +1152,8 @@ async function runCase(suite, kase) {
let gateLeaked = false;
const gateChecked = new Set();
let decisions = 0;
missedRows.clear();
asked.length = 0;
/** 人加行只加一次;加的那家进没进计划,在办中盯(放行会把草稿消费掉,收工再看就晚了) */
let addedRows = false;
let planned = false;
@@ -1351,6 +1380,23 @@ async function runCase(suite, kase) {
ok = false;
}
// 「超限才叫人」是 A4 的要害:该叫的那一单没叫,等于底价门禁是摆设
if (missedRows.size > 0) {
console.log(` ⚠️ 案例点名要填的行,整例跑完也没在件上出现过(${missedRows.size} 处:${[...missedRows].slice(0, 3).join('、')}…)—— 判失败`);
ok = false;
}
/*
* **决策卡要数「问的是哪件事」,不是笼统数张数**(2026-08-27:两颗缺库一张创建卡都没问,
* 而审核卡也是决策卡 —— `decisions > 0` 于是恒真,该问没问照样绿)。
*/
if (kase.expectAsks !== undefined) {
for (const { re, count } of kase.expectAsks) {
const got = asked.filter((a) => re.test(a)).length;
if (got < count) {
console.log(` ⚠️ 该问的没问够:${re} 期望 ≥${count} 张,实际 ${got} 张 —— 判失败`);
ok = false;
}
}
}
if (kase.expectDecision && decisions === 0) {
console.log(' ⚠️ 超限条目没走决策卡 —— 判失败');
ok = false;
@@ -1401,6 +1447,11 @@ async function runCase(suite, kase) {
return ok && (!kase.expectPort || ports.includes(kase.expectPort));
}
/** 这一例里「案例点名要填、而件上找不到」的行 —— 每例开头清空,收尾判失败 */
const missedRows = new Set();
/** 这一例里模型问过的每一句(决策卡的 ask)—— 收尾按「问的是哪件事」核,不是笼统数张数 */
const asked = [];
async function main() {
const which = process.argv[2] ?? 'all';
const only = process.argv[3] === undefined ? undefined : Number(process.argv[3]);
@@ -1414,7 +1465,16 @@ async function main() {
for (const [i, kase] of suite.cases.entries()) {
if (only !== undefined && i !== only) continue;
total += 1;
if (await runCase(suite, kase)) pass += 1;
/*
* **一例翻车不该拖垮整套**(2026-08-27 实测:P-10 那张卡零行、闸如实拦着,
* 脚本没东西可填、抛出去,后面两例连跑都没跑)。判失败、记下来、接着跑下一例 ——
* 一套五例的价值就在于「哪几例过、哪几例没过」,死在半路等于什么都没测出来。
*/
try {
if (await runCase(suite, kase)) pass += 1;
} catch (error) {
console.log(` ✗ 这一例中途出错,判失败,接着跑下一例:${String(error.message ?? error).slice(0, 200)}`);
}
}
}
console.log(`\n${pass}/${total} 通过;记得 pnpm --filter @app/api reset-runs 清运行数据`);