Archived
fix(w05): 评估输入清单两条 Critical 回归 —— 主键丢钥匙、必填填不了
定向复审发现上一轮模版重做(00133c2)新引入两条回归,都出在 sub_eval.input_gap 的缺口表:
- item_key 那格丢了 data-col:一单 11 行,item_key 逐行不同,服务端 resolveRowKey 既在件上
找不到它、又不是「全表一致」的案号型列(那条路只对 caseKey 成立),人保存任何一行都会
「认不出它是哪一行」。补回 <span data-col="item_key">,并把「加一行」提示补上「键必须填」。
- status 声明 required:true,又给了「加一行」,却被降成只读徽标——人新加的行永远没有格子
填这一列,_missing 恒正、提交闸永远拦着(墙不配路)。改回 E04 执行回执同款的混排:
<select class="jc-cell" data-col="status"> 挨着 <span data-class-of="status"> 徽标,
只读徽标不裹 .jc-vcell(它没有孪生件),编辑态天然不被 :has(+ .jc-cell) 那条规则藏起来,
不用动 BIND_CSS。
自查确认另两张可编辑件(parts.profile 的 internal_pn、parts.document 的 internal_pn+doc_seq)
的主键 data-col 本就都在,不是这次回归的范围。
补两条回归网(新 describe「可编辑件的主键与必填列」):①三张可编辑件每个非 caseKey 的主键列
都有 data-col;②每个 required:true 且落在可编辑件上的列都有 data-col。两条从
manifest.declarations.ledger 现读,不是照抄字面值,以后同类回归会自动变红。
P08_CSS 的「空行」复审点:重新用 hexdump 核对源文件 `ACT-WORK-05-数据工单-01-芯片主数据
创建.html` 第 86-89 行(两个 <style> 标签接缝),字节层面确认原文没有空行
(`...border-color:var(--line)}\n.tbl-gap{...}\n</style>\n<style>\n/* ===== 视觉补充段...`,
中间没有任何空行或隐藏字符);target-style.ts 的 P08_CSS 与该区间逐字节相同(Python diff
再次核验,长度 7531 完全一致)。没有改动这段内容——加一行会让它偏离已验证正确的源文件,
详见报告里贴的十六进制证据。
升版本号 1.1.0 → 1.1.1;pnpm activities:install 已验证装包成功。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJcX8A6TWp4GRs41TYryEh
This commit is contained in:
@@ -2,8 +2,9 @@
|
||||
* ACT-WORK-05 差异评估的包内自测 —— **只准 import @sdk / @contracts / @sfeel**。
|
||||
* 案例活动没有 `run`,自测不跑回合;测的是清单本身与授权面对齐,结构照 E04 / I01。
|
||||
*
|
||||
* 六组:清单本身合规 / 台账声明 / 案例模型与清单的对齐 / 报告模版:编辑面与只读面各就各位 /
|
||||
* 徽标别名与值域相关的坑(2026-08-27 实测账,回归网)/ 活动入口。
|
||||
* 七组:清单本身合规 / 台账声明 / 案例模型与清单的对齐 / 报告模版:编辑面与只读面各就各位 /
|
||||
* 徽标别名与值域相关的坑(2026-08-27 实测账,回归网)/ 可编辑件的主键与必填列
|
||||
* (2026-08-27 复审,回归网)/ 活动入口。
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { activityManifestSchema } from '@contracts';
|
||||
@@ -304,6 +305,56 @@ describe('徽标别名与值域相关的坑(2026-08-27 实测账,回归网)', ()
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
* 2026-08-27 定向复审逮住的两条 Critical(都是这一轮版面重做新引入的回归,不是原有的坑):
|
||||
* ① `sub_eval.input_gap` 的「键」(`item_key`)那一格丢了 `data-col` —— 一单 11 行,`item_key`
|
||||
* 逐行不同,人保存**任何一行**时服务端 `resolveRowKey` 凑不出主键(它既不在件上、
|
||||
* 又不是「全表一致」的那种案号型列),整格落不下去;
|
||||
* ② `sub_eval.input_gap.status` 声明 `required: true`,件上又有「+ 加一行」——
|
||||
* 降成只读徽标后,人新加的行永远没有格子能把这一列填上,`_missing` 恒为正、
|
||||
* 提交闸永远拦着,这是「墙不配路」的死路形态。
|
||||
* 两条各配一张回归网,防的是同一类事故再出现在别的字段上。
|
||||
*/
|
||||
describe('可编辑件的主键与必填列(2026-08-27 复审:主键丢钥匙 / 必填填不了,两条 Critical 回归)', () => {
|
||||
/** 三张真能编辑的件与它们各自绑定的台账对象 */
|
||||
const EDITABLE: ReadonlyArray<{ view: string; domain: string; object: string }> = [
|
||||
{ view: 'p08-master-create', domain: 'parts', object: 'profile' },
|
||||
{ view: 'p10-document-create', domain: 'parts', object: 'document' },
|
||||
{ view: 'eval-input-list', domain: D, object: 'input_gap' },
|
||||
];
|
||||
|
||||
it('每一个主键列都有 data-col —— 它不是编辑面,是行的钥匙,丢了就整行保存不下去', () => {
|
||||
for (const { view, domain, object } of EDITABLE) {
|
||||
const table = byAddress(domain, object);
|
||||
/*
|
||||
* `caseKey` 声明的那一列(如 `eval_ref`)是例外:它是「一单一号,全表当然一致」的
|
||||
* 案号型主键(与 I01 的 `round_ref` 同款),件上压根不摆,服务端 `resolveRowKey`
|
||||
* 按「全表一致」自动补上(`apps/api/src/app/routes/desk.ts` 注释里点名的那条路)——
|
||||
* 摆出来给人填反而是错的(那会让人以为能按行改案号)。真正逐行不同、必须挂
|
||||
* `data-col` 的,是主键里除 caseKey 之外的那几列(如 `item_key`)。
|
||||
*/
|
||||
const pk = (table?.fields.filter((f) => f.primaryKey).map((f) => f.name) ?? []).filter((name) => name !== table?.caseKey);
|
||||
expect(pk.length, `${domain}.${object} 没有非 caseKey 的主键列`).toBeGreaterThan(0);
|
||||
const html = viewHtml(view);
|
||||
for (const col of pk) {
|
||||
expect(html, `${view}: 主键列 ${domain}.${object}.${col} 缺 data-col`).toContain(`data-col="${col}"`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('可编辑件上,每一个 required:true 的列都有真能填的控件(data-col)—— 必填但填不了是墙不配路', () => {
|
||||
for (const { view, domain, object } of EDITABLE) {
|
||||
const table = byAddress(domain, object);
|
||||
const required = table?.fields.filter((f) => f.required === true).map((f) => f.name) ?? [];
|
||||
expect(required.length, `${domain}.${object} 没有声明 required 列`).toBeGreaterThan(0);
|
||||
const html = viewHtml(view);
|
||||
for (const col of required) {
|
||||
expect(html, `${view}: 必填列 ${domain}.${object}.${col} 没有可填的控件`).toContain(`data-col="${col}"`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('活动入口', () => {
|
||||
it('没有 run —— 行为全在清单里', () => {
|
||||
expect(activity.run).toBeUndefined();
|
||||
|
||||
@@ -84,7 +84,7 @@ export const manifest: ActivityManifest = {
|
||||
identity: {
|
||||
activityId: ACTIVITY_ID,
|
||||
name: 'ACT-WORK-05 · 差异评估',
|
||||
packageVersion: '1.1.0',
|
||||
packageVersion: '1.1.1',
|
||||
category: '需求分析与方案匹配',
|
||||
sdkVersion: '0.1.0-m5',
|
||||
checksum: 'dev-checksum-part-substitution-assessment',
|
||||
|
||||
@@ -436,6 +436,7 @@ const PN_CHECK_TABLE = `<div class="jc-tbl-wrap"><table>
|
||||
const GAP_TABLE = `<div class="jc-tbl-wrap"><table id="tbl">
|
||||
<thead><tr>
|
||||
<th style="width:38px">#</th>
|
||||
<th style="width:120px" data-h="键">键</th>
|
||||
<th data-h="输入项">输入项</th>
|
||||
<th data-h="来源">来源</th>
|
||||
<th data-h="状态">状态</th>
|
||||
@@ -444,9 +445,10 @@ const GAP_TABLE = `<div class="jc-tbl-wrap"><table id="tbl">
|
||||
</tr></thead>
|
||||
<tbody data-rows="mine:${D}.input_gap" data-edit="${D}.input_gap"><tr>
|
||||
<td class="rn"><span class="jc-rn-num"></span><button class="jc-rowdel" type="button" title="删除此行" data-edit-del="${D}.input_gap">×</button></td>
|
||||
<td>${cell('item_key', 'mono')}</td>
|
||||
<td>${cell('input_item')}</td>
|
||||
<td>${cell('source_ledger', 'mono')}</td>
|
||||
<td>${badge('st', 'status', true)}</td>
|
||||
<td>${select('status', [['gap', '待补'], ['default', '默认·可改'], ['ok', '齐备']], true)}${badge('st', 'status')}</td>
|
||||
<td>${cell('detail')}</td>
|
||||
<td class="sup" data-class-of="status">${cell('supplement')}</td>
|
||||
</tr></tbody>
|
||||
@@ -473,7 +475,7 @@ export const EVAL_INPUT_LIST = doc({
|
||||
gapbar(`${D}_input_gap`, '补充内容') +
|
||||
editGate(`${D}.input_gap`, `<b>还有 <span data-slot="${D}_input_gap_missing"></span> 项待补 / 待确认</b>,点「编辑」在「补充内容」列填入 —— 已绑定那几行的「输入项/来源/绑定值」抄的是启动入参,发现记录本身有误请退回触发方重新启动,不要在这里改`) +
|
||||
GAP_TABLE +
|
||||
addrow(`${D}.input_gap`, '+ 加一行(补充资料项)', '新加行的「输入项」与「补充内容」为必填;删一行 = 该输入项不适用;补不了的写「留 UNKNOWN」或「挂验证任务」') +
|
||||
addrow(`${D}.input_gap`, '+ 加一行(补充资料项)', '新行的「键」必须写(它是这一行的钥匙,写一个英文短名,如 thermal_note);「输入项」与「补充内容」也是必填;删一行 = 该输入项不适用;补不了的写「留 UNKNOWN」或「挂验证任务」') +
|
||||
flow(
|
||||
'<b>审批 / 提交:</b>本工单只承载内容;「提交」请在对话区的【执行卡】中进行。<b>提交后去向:</b>进入步骤 2 · AI 读取与标准化,仍缺失的项将按 UNKNOWN 进入差异评估。<b>注意:</b>启动参数如有误,需退回触发方修订后重新触发,本单不可改。',
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user