fix(w05): 评审回来的一条 Critical、一条 Important、两条 Minor

Critical:S1 数据工单的 gateLedgers 带着 parts.chip_type,而这张件没有任何手段
写它(选类型走 data-options 下拉现读,不是编辑表)—— mine:parts.chip_type 永远
是空数组,desk.ts 的 emptyGate 永远判「这一单还一行都没有」,确认钮永久按不下去,
三张真被编辑的表填得再全也一样。删掉 parts.chip_type,只留真被这张件写过的三张;
注释写明这是永久决定,不是等 Task 7b 补了新建类型的编辑表就该还原(主路是从下拉
挑已有类型,那时这张表天然零行,「零行=没干完」这条闸的前提对它压根不成立)。
新增 apps/api 侧回归探针(调用生产 emptyGate,不抄实现):证明旧配置确实会永久
卡死、新配置在同一份数据下真的放行。

Important:BIND_COMMON 的序号计数器规则只认 .tbl-wrap,而三张表的外壳是
.jc-tbl-wrap(继承自已删除的旧 P08_MASTER_CREATE 同一个坑)—— 两个 class 对不上,
「#」列在只读态与编辑态下逐行空白。补上 .jc-tbl-wrap,钉一条结构测试。

Minor:①block③ 的注释「只两栏可改」没说全 —— internal_pn/param_name 也走 cell()
(主键格必挂 data-col 是既定约定,行的钥匙),补全这句话;②data-class-of="gate_reason"
在中文自由文本上永远算不出 v-token,是源码里躺着的一个永远不起作用的属性——删掉,
显隐只留 :has(:empty) 一处,brief 给的那条断言同步改成断真实机制。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
xcs
2026-08-29 19:11:03 +08:00
co-authored by Claude Opus 5
parent fdcd1f88a7
commit 40daa6c9f7
5 changed files with 128 additions and 17 deletions
@@ -442,14 +442,40 @@ describe('件① 评估输入补全', () => {
}
});
it('模版不算不判:没有内联脚本,红带的显隐交给样式表', () => {
/*
* 2026-08-29 评审 Minor:brief 原话是「红带显隐用 data-class-of」,但 gate_reason 是
* 中文自由文本 —— classToken 只留 [a-z0-9-],中文字符全被剥空,不论空串还是有内容的
* 中文句子算出来的 token 都是空的,这条路本来就走不通(不是本任务的臆断,评审读了
* view-render.ts 的 classToken 实现确认)。真正管显隐的是 data-blank 出的空文本节点
* 配 CSS :has(:empty) ——源码里不留一个永远不起作用的 data-class-of 属性。
*/
it('模版不算不判:没有内联脚本,红带的显隐交给样式表(:has(:empty),不是 gate_reason 上算不出来的 data-class-of)', () => {
expect(html).not.toContain('<script');
expect(html).toContain('data-class-of="gate_reason"');
expect(html).not.toContain('data-class-of="gate_reason"');
expect(html).toContain('class="jc-gate-text" data-slot="gate_reason" data-blank');
expect(html).toContain('.jc-gate-bar:has(.jc-gate-text:empty)');
});
it('表宽超出要能横着滑 —— 不许写成 overflow:hidden(E04/I01 抄错过一次)', () => {
expect(html).not.toMatch(/\.jc-tbl-wrap\s*\{[^}]*overflow\s*:\s*hidden/);
});
/*
* 2026-08-29 评审 Important:BIND_COMMON 的序号计数器规则原来只认 `.tbl-wrap`
* (继承自已删除的旧 P08_MASTER_CREATE,同一个 wrapper class,同一个坑),
* 而这张件的三张表全用平台的 `.jc-tbl-wrap` —— 两个 class 对不上,计数器永不触发,
* 只读态与编辑态下「#」列逐行都是空白。钉死 `.jc-tbl-wrap` 现在也接了这五条规则,
* 且这张件确实只用 `.jc-tbl-wrap`(没有表在用没打这条补丁就会数不出来的 `.tbl-wrap`)。
*/
it('三张表的序号列真的会数:.jc-tbl-wrap 也接了 CSS 计数器(不再只认 .tbl-wrap)', () => {
expect(html).toMatch(/\.jc-tbl-wrap\s+table\s*,\s*\.tbl-wrap\s+table\s*\{\s*counter-reset:\s*rn;?\s*\}/);
expect(html).toMatch(/\.jc-tbl-wrap\s+table\s+td\.rn\s*,\s*\.tbl-wrap\s+table\s+td\.rn\s*\{\s*counter-increment:\s*rn;?\s*\}/);
expect(html).toMatch(/\.jc-tbl-wrap\s+table\s+td\.rn\s+\.jc-rn-num::before\s*,\s*\.tbl-wrap\s+table\s+td\.rn\s+\.jc-rn-num::before\s*\{\s*content:\s*counter\(rn\);?\s*\}/);
// 这张件的三张表都走 .jc-tbl-wrap(没有 .tbl-wrap)—— 补丁真的接在会用到的类上
expect(html).not.toContain('class="tbl-wrap"');
const jcTblWrapCount = html.match(/class="jc-tbl-wrap"/g)?.length ?? 0;
expect(jcTblWrapCount).toBe(3);
});
});
/*
@@ -188,11 +188,21 @@ describe('S1 配方', () => {
expect(when).toContain('parts_parameter_missing > 0');
});
it('卡:数据工单、四张表都在闸上、且有 basis(基座拒发 basis 为空的工单)', () => {
/*
* 2026-08-29 评审 Critical(Task 7 走查):`gateLedgers` 一度带着 `parts.chip_type`,
* 而 `input-supplement` 这张件没有任何 `data-edit="parts.chip_type"`(选类型走
* `data-options` 下拉现读,不写这张表)—— `mine:parts.chip_type` 永远是空数组,
* `desk.ts` 的 `emptyGate` 会永远判「这一单还一行都没有」,提交钮永久按不下去。
* **`parts.chip_type` 永久不列进这张卡的闸**(不是等新建类型的编辑表补上就该还原 ——
* 见 `case-model.ts` 该处注释:主路是从下拉挑一个已有类型,那时这张表天然零行,
* `emptyGate`「这张卡就是来建它的」这条语义对一张只是有时候才写的表根本不成立)。
*/
it('卡:数据工单、三张真被这张件写过的表在闸上(parts.chip_type 不在——它没有编辑手段,列了就永久卡死)、且有 basis(基座拒发 basis 为空的工单)', () => {
const card = acts[4];
expect(card?.kind === 'card' && card.as).toBe('execution');
expect(card?.kind === 'card' && card.variant).toBe('data');
expect(card?.kind === 'card' && card.gateLedgers).toEqual(['parts.chip_type', 'parts.type_param', 'parts.profile', 'parts.parameter']);
expect(card?.kind === 'card' && card.gateLedgers).toEqual(['parts.type_param', 'parts.profile', 'parts.parameter']);
expect((card?.kind === 'card' ? card.gateLedgers ?? [] : [])).not.toContain('parts.chip_type');
expect((card?.kind === 'card' ? card.basis ?? [] : []).length).toBeGreaterThan(0);
expect((card?.kind === 'card' ? card.guide ?? [] : []).length).toBeGreaterThanOrEqual(3);
});