@qilitt-mickey/vue3-temp-skill 1.1.50 → 1.1.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/parser/fixtures/changeset-fullpage-restore.json +10 -8
- package/parser/fixtures/changeset-neg6-g9-identity.json +39 -0
- package/parser/fixtures/changeset-neg7-g10-dims.json +57 -0
- package/parser/fixtures/changeset-neg8-g11-oracle.json +57 -0
- package/parser/fixtures/registry-sample.json +2 -2
- package/parser/index.js +127 -29
- package/parser/regression.js +27 -3
- package/references/design-apply.md +8 -2
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$comment": "端到端示例 · 整页场景还原(对照效果图逐模块提取的完整交付样例,模拟设计技能真实产出)。G8 模式闸正例:mode=restore + scheme + oracle(含 mockup) + coverage(含 registry)
|
|
2
|
+
"$comment": "端到端示例 · 整页场景还原(对照效果图逐模块提取的完整交付样例,模拟设计技能真实产出)。G8 模式闸正例:mode=restore + scheme + oracle(含 mockup) + coverage(含 registry) 齐备,且通过 G9 身份闸(registry-sample.json 属 default×admin,与变更集一致)与 G10 dims 兑现闸(sample#1-4/sample#6 适用项的 dims 全部给出;sample#5 选择列为条件项、效果图未标注不适用)。覆盖率计数以登记表当场重算为准(applicable=5:4 条恒存在 + 1 条效果图命中)。覆盖:global 主题 + 壳层全模块 + 列表页全字段 + 表格细粒度点位(操作列形态/状态Tag/金额对齐/缩略图)+ pending 新点位。值口径演示:主题色用语义值(钴蓝-N/错误色)、尺寸用数值字面量(28px/40px 等,设计侧 v1.0 协议第 3 条合法通道)、灰阶用临时主题 hex + notes 申报。业务功能差异(新增运单按钮功能、demo 演示按钮去留)不在本变更集范围,走项目侧业务闭环开发(双层交付)。真实 186 条登记表(references/.../scenes/admin/restore-registry.json)见 M 步与项目侧实测;本夹具的 registry 指向 6 条回归夹具表,避免回归依赖跨技能实物。运行:node parser/index.js match <本文件>(cwd 为 skill 根)。",
|
|
3
3
|
"schema": "design.changeset/1.0",
|
|
4
4
|
"changeset_version": "1.0.0",
|
|
5
5
|
"mapping_version": "1.0.0",
|
|
@@ -41,12 +41,14 @@
|
|
|
41
41
|
{ "id": "admin.layout.tabs", "form": "chrome", "style": { "bg": "#FFFFFF" } },
|
|
42
42
|
{
|
|
43
43
|
"id": "admin.content.table.header_cell",
|
|
44
|
-
"style": { "height": "48px", "bg": "#FAFAFA", "font_weight": "中等" }
|
|
44
|
+
"style": { "height": "48px", "padding": "16px", "bg": "#FAFAFA", "font_weight": "中等", "text_align": "左对齐", "nowrap": "不换行" },
|
|
45
|
+
"layer": { "height": "host", "padding": "host", "bg": "host", "font_weight": "host", "text_align": "inner", "nowrap": "inner" },
|
|
46
|
+
"suppress_inner": true
|
|
45
47
|
},
|
|
46
48
|
{
|
|
47
49
|
"id": "admin.content.table.cell",
|
|
48
|
-
"style": { "padding_y": "8px", "vertical_align": "middle" },
|
|
49
|
-
"layer": { "padding_y": "inner", "vertical_align": "inner" },
|
|
50
|
+
"style": { "padding": "16px", "padding_y": "8px", "vertical_align": "middle" },
|
|
51
|
+
"layer": { "padding": "host", "padding_y": "inner", "vertical_align": "inner" },
|
|
50
52
|
"suppress_inner": true
|
|
51
53
|
},
|
|
52
54
|
{
|
|
@@ -54,6 +56,7 @@
|
|
|
54
56
|
"form": "filled",
|
|
55
57
|
"style": { "bg": "#E8F3FF", "text_color": "钴蓝-5", "radius": "小圆角" }
|
|
56
58
|
},
|
|
59
|
+
{ "id": "component.tag.status", "form": "filled", "style": { "height": "24px", "radius": "小圆角", "bg_color": "#F6FFED" } },
|
|
57
60
|
{
|
|
58
61
|
"id": "admin.content.page_header",
|
|
59
62
|
"style": { "title_size": "20px", "title_weight": "加粗", "desc_color": "钴蓝-3", "actions_gap": "8px" }
|
|
@@ -74,7 +77,6 @@
|
|
|
74
77
|
{ "id": "admin.content.table.area", "style": { "header_bg": "#FAFAFA", "row_hover_bg": "#FAFAFA", "radius": "小圆角" } },
|
|
75
78
|
{ "id": "admin.content.table.cell_amount", "style": { "align": "right", "font_variant_numeric": "等宽数字" } },
|
|
76
79
|
{ "id": "admin.content.table.cell_thumb", "style": { "thumb_width": "40px", "thumb_height": "40px", "thumb_radius": "小圆角" } },
|
|
77
|
-
{ "id": "component.tag.status", "form": "filled", "style": { "height": "24px", "radius": "小圆角" } },
|
|
78
80
|
{ "id": "component.button.danger", "style": { "bg_color": "错误色", "border_color": "错误色", "text_color": "#FFFFFF" } },
|
|
79
81
|
{ "id": "admin.content.pagination", "style": { "active_bg": "钴蓝-5", "active_color": "#FFFFFF" } }
|
|
80
82
|
],
|
|
@@ -104,10 +106,10 @@
|
|
|
104
106
|
]
|
|
105
107
|
},
|
|
106
108
|
"coverage": {
|
|
107
|
-
"registry": "registry-sample.json",
|
|
109
|
+
"registry": "parser/fixtures/registry-sample.json",
|
|
108
110
|
"registrable": 6,
|
|
109
|
-
"applicable":
|
|
110
|
-
"covered":
|
|
111
|
+
"applicable": 5,
|
|
112
|
+
"covered": 5,
|
|
111
113
|
"gaps": []
|
|
112
114
|
},
|
|
113
115
|
"pending": [
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "G9 登记表身份闸负例:mode=restore 且基线三件套齐备(过 G8),但 coverage.registry 指向身份错配的登记表——变更集 scheme=tangerine,登记表 design_scheme=default → 凡身份对不上的表视同没有表。历史缺口:G8 只验 coverage.registry 是非空字符串,拿别的方案/场景的登记表甚至 6 条回归小表都能过 G8,覆盖率分母被偷换,面包屑/顶栏图标/表头 nowrap 等点位从分母消失,欠声明不可数。预期:match 打印「G9 登记表身份闸」并 exit 1。",
|
|
3
|
+
"schema": "design.changeset/1.0",
|
|
4
|
+
"changeset_version": "1.0.0",
|
|
5
|
+
"mapping_version": "1.0.0",
|
|
6
|
+
"scene": "admin",
|
|
7
|
+
"scheme": "tangerine",
|
|
8
|
+
"mode": "restore",
|
|
9
|
+
"layout_type": "vertical",
|
|
10
|
+
"global": { "brand_primary": "橘橙-5" },
|
|
11
|
+
"changes": [
|
|
12
|
+
{ "id": "admin.layout.sidebar.menu", "style": { "menu_bg": "橘橙-10", "menu_active_bg": "橘橙-5" } },
|
|
13
|
+
{ "id": "admin.content.table.header_cell", "style": { "height": "48px", "padding": "16px", "font_weight": "中等", "text_align": "左对齐", "nowrap": "不换行" }, "layer": { "height": "host", "padding": "host", "font_weight": "host", "text_align": "inner", "nowrap": "inner" }, "suppress_inner": true },
|
|
14
|
+
{ "id": "admin.content.table.cell", "style": { "padding": "16px", "padding_y": "8px", "vertical_align": "middle" }, "layer": { "padding": "host", "padding_y": "inner", "vertical_align": "inner" }, "suppress_inner": true },
|
|
15
|
+
{ "id": "component.tag.status", "form": "filled", "style": { "height": "24px", "radius": "小圆角", "bg_color": "#F6FFED" } },
|
|
16
|
+
{ "id": "component.button.danger", "style": { "bg_color": "错误色" } },
|
|
17
|
+
{ "id": "admin.content.pagination", "style": { "active_bg": "橘橙-5", "active_color": "#FFFFFF" } }
|
|
18
|
+
],
|
|
19
|
+
"oracle": {
|
|
20
|
+
"mockup": "verify/运单管理-钴蓝.html",
|
|
21
|
+
"theme_mapping": { "from": "钴蓝", "to": "橘橙" },
|
|
22
|
+
"sids": [
|
|
23
|
+
"admin.layout.sidebar.menu",
|
|
24
|
+
"admin.content.table.header_cell",
|
|
25
|
+
"admin.content.table.cell",
|
|
26
|
+
"component.tag.status",
|
|
27
|
+
"component.button.danger",
|
|
28
|
+
"admin.content.pagination"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"coverage": {
|
|
32
|
+
"registry": "parser/fixtures/registry-sample.json",
|
|
33
|
+
"registrable": 6,
|
|
34
|
+
"applicable": 5,
|
|
35
|
+
"covered": 5,
|
|
36
|
+
"gaps": []
|
|
37
|
+
},
|
|
38
|
+
"notes": "本夹具用于回归 G9 身份闸,不是真实设计交付件。变更集宣称橘橙(tangerine)方案,登记表却是 default 方案的表——设计侧真实交付时对应事故形态:橘橙还原却引用钴蓝方案的登记表,186 条壳层+表格分母被偷换成 6 条小表。oracle 已声明 theme_mapping 钴蓝→橘橙(同构异色合法),因此本夹具若登记表身份正确则其余闸门全绿,唯一拦截点就是 G9——保证负例的归因纯净。"
|
|
39
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "G10 dims 兑现闸负例:mode=restore、基线三件套齐备、登记表身份一致(过 G8/G9),但 admin.content.table.header_cell 的 ID 已声明却缺 nowrap / text_align 维度(表头竖排 = nowrap 丢失的机检复现件)——「点位在、细节丢」正是样式细节不还原的机制成因。历史缺口:兑现只数 ID 出现,漏给关键维度也算已兑现。预期:match 打印「G10」与「缺 dims=」并 exit 1。",
|
|
3
|
+
"schema": "design.changeset/1.0",
|
|
4
|
+
"changeset_version": "1.0.0",
|
|
5
|
+
"mapping_version": "1.0.0",
|
|
6
|
+
"scene": "admin",
|
|
7
|
+
"scheme": "default",
|
|
8
|
+
"mode": "restore",
|
|
9
|
+
"layout_type": "vertical",
|
|
10
|
+
"global": { "brand_primary": "钴蓝-5" },
|
|
11
|
+
"changes": [
|
|
12
|
+
{
|
|
13
|
+
"id": "admin.content.table.header_cell",
|
|
14
|
+
"style": { "height": "48px", "padding": "16px", "font_weight": "中等" },
|
|
15
|
+
"layer": { "height": "host", "padding": "host", "font_weight": "host" },
|
|
16
|
+
"suppress_inner": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "admin.content.table.cell",
|
|
20
|
+
"style": { "padding": "16px", "padding_y": "8px", "vertical_align": "middle" },
|
|
21
|
+
"layer": { "padding": "host", "padding_y": "inner", "vertical_align": "inner" },
|
|
22
|
+
"suppress_inner": true
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "admin.content.table.cell_amount",
|
|
26
|
+
"style": { "align": "right" }
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "admin.content.table.cell_status",
|
|
30
|
+
"form": "filled",
|
|
31
|
+
"style": { "bg": "#E8F3FF" }
|
|
32
|
+
},
|
|
33
|
+
{ "id": "component.tag.status", "form": "filled", "style": { "height": "24px", "radius": "小圆角", "bg_color": "#F6FFED" } },
|
|
34
|
+
{ "id": "component.button.danger", "style": { "bg_color": "错误色" } },
|
|
35
|
+
{ "id": "admin.content.pagination", "style": { "active_bg": "钴蓝-5", "active_color": "#FFFFFF" } }
|
|
36
|
+
],
|
|
37
|
+
"oracle": {
|
|
38
|
+
"mockup": "verify/运单管理-钴蓝.html",
|
|
39
|
+
"sids": [
|
|
40
|
+
"admin.content.table.header_cell",
|
|
41
|
+
"admin.content.table.cell",
|
|
42
|
+
"admin.content.table.cell_amount",
|
|
43
|
+
"admin.content.table.cell_status",
|
|
44
|
+
"component.tag.status",
|
|
45
|
+
"component.button.danger",
|
|
46
|
+
"admin.content.pagination"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"coverage": {
|
|
50
|
+
"registry": "parser/fixtures/registry-sample.json",
|
|
51
|
+
"registrable": 6,
|
|
52
|
+
"applicable": 5,
|
|
53
|
+
"covered": 5,
|
|
54
|
+
"gaps": []
|
|
55
|
+
},
|
|
56
|
+
"notes": "本夹具用于回归 G10 dims 闸,不是真实设计交付件。与 H 正例的差集只有一处:header_cell 少了 text_align / nowrap 两个维度(及其 layer)——ID 级覆盖率 100%,但表头竖排(nowrap 丢失)这类「点位在、细节丢」症状在旧口径下一路绿灯。G10 生效后 dims 缺口与欠声明同级阻断。所有条目均带 suppress_inner 硬闸所需声明、tag.status 的 bg_color 维度齐备,保证唯一拦截点 = G10。"
|
|
57
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "G11 oracle 基线硬闸负例:mode=restore、三件套齐备、登记表身份一致(过 G8/G9),但效果图是钴蓝主题、变更集主色是橘橙,且未声明 theme_mapping 同构异色复用 → 主题错配。历史缺口:基线断裂只打 ⚠ 软提示就继续交付,verify 无从做 1:1 证明。预期:match 打印「G11」与「主题错配」并 exit 1。",
|
|
3
|
+
"schema": "design.changeset/1.0",
|
|
4
|
+
"changeset_version": "1.0.0",
|
|
5
|
+
"mapping_version": "1.0.0",
|
|
6
|
+
"scene": "admin",
|
|
7
|
+
"scheme": "default",
|
|
8
|
+
"mode": "restore",
|
|
9
|
+
"layout_type": "vertical",
|
|
10
|
+
"global": { "brand_primary": "橘橙-5" },
|
|
11
|
+
"changes": [
|
|
12
|
+
{
|
|
13
|
+
"id": "admin.content.table.header_cell",
|
|
14
|
+
"style": { "height": "48px", "padding": "16px", "font_weight": "中等", "text_align": "左对齐", "nowrap": "不换行" },
|
|
15
|
+
"layer": { "height": "host", "padding": "host", "font_weight": "host", "text_align": "inner", "nowrap": "inner" },
|
|
16
|
+
"suppress_inner": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "admin.content.table.cell",
|
|
20
|
+
"style": { "padding": "16px", "padding_y": "8px", "vertical_align": "middle" },
|
|
21
|
+
"layer": { "padding": "host", "padding_y": "inner", "vertical_align": "inner" },
|
|
22
|
+
"suppress_inner": true
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "admin.content.table.cell_amount",
|
|
26
|
+
"style": { "align": "right" }
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "admin.content.table.cell_status",
|
|
30
|
+
"form": "filled",
|
|
31
|
+
"style": { "bg": "#FFF3E6" }
|
|
32
|
+
},
|
|
33
|
+
{ "id": "component.tag.status", "form": "filled", "style": { "height": "24px", "radius": "小圆角", "bg_color": "#F6FFED" } },
|
|
34
|
+
{ "id": "component.button.danger", "style": { "bg_color": "错误色" } },
|
|
35
|
+
{ "id": "admin.content.pagination", "style": { "active_bg": "橘橙-5", "active_color": "#FFFFFF" } }
|
|
36
|
+
],
|
|
37
|
+
"oracle": {
|
|
38
|
+
"mockup": "verify/运单管理-钴蓝.html",
|
|
39
|
+
"sids": [
|
|
40
|
+
"admin.content.table.header_cell",
|
|
41
|
+
"admin.content.table.cell",
|
|
42
|
+
"admin.content.table.cell_amount",
|
|
43
|
+
"admin.content.table.cell_status",
|
|
44
|
+
"component.tag.status",
|
|
45
|
+
"component.button.danger",
|
|
46
|
+
"admin.content.pagination"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"coverage": {
|
|
50
|
+
"registry": "parser/fixtures/registry-sample.json",
|
|
51
|
+
"registrable": 6,
|
|
52
|
+
"applicable": 5,
|
|
53
|
+
"covered": 5,
|
|
54
|
+
"gaps": []
|
|
55
|
+
},
|
|
56
|
+
"notes": "本夹具用于回归 G11 oracle 闸,不是真实设计交付件。与 H 正例的差集只有两处:global.brand_primary 改橘橙、且 oracle 不带 theme_mapping——「橘橙还原却拿钴蓝效果图当基线」正是橘橙主题还原事故的直接形态(registry 无橘橙沉淀基线时最易发生)。若设计侧补 theme_mapping { from: 钴蓝, to: 橘橙 } 即转合法(同构异色复用)。"
|
|
57
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$comment": "回归夹具 · 登记表样例(不是真实交付件)。6 条登记项示范粒度与字段口径:4 条 always(恒存在,必登)、2 条条件项。用于 M/N
|
|
2
|
+
"$comment": "回归夹具 · 登记表样例(不是真实交付件)。6 条登记项示范粒度与字段口径:4 条 always(恒存在,必登)、2 条条件项。用于 M/N/H/R/S/T 步:M 校验覆盖率重算能报出欠声明并 exit 1,N 校验通道核验能跑通,H 为 G8/G9/G10 正例,R/S/T 分别负例 G9 身份错配 / G10 dims 缺维度 / G11 主题错配。sample#1 的 dims 含 text_align/nowrap(表头竖排事故的 G10 机检锚点:S 步夹具故意漏给这两维)。⚠ selection_column / cell 等点位词典已补建通道,本夹具不再示范 pending 标注(pending 演示见 registry-bad.json 的硬缺口反例)。",
|
|
3
3
|
"schema": "design.restore-registry/1.0",
|
|
4
4
|
"design_scheme": "default",
|
|
5
5
|
"scene": "admin",
|
|
6
6
|
"counts": { "total": 6 },
|
|
7
7
|
"items": [
|
|
8
|
-
{ "rule": "sample#1", "group": "样例·表格区", "sid": "admin.content.table.header_cell", "dims": ["height", "padding"], "channel": ["style", "layer"], "source": "both", "always": true },
|
|
8
|
+
{ "rule": "sample#1", "group": "样例·表格区", "sid": "admin.content.table.header_cell", "dims": ["height", "padding", "text_align", "nowrap"], "channel": ["style", "layer"], "source": "both", "always": true },
|
|
9
9
|
{ "rule": "sample#2", "group": "样例·表格区", "sid": "admin.content.table.cell", "dims": ["padding", "padding_y"], "channel": ["style", "layer"], "source": "both", "always": true },
|
|
10
10
|
{ "rule": "sample#3", "group": "样例·金额列", "sid": "admin.content.table.cell_amount", "dims": ["align"], "channel": ["style", "structure_ops"], "source": "spec", "always": true },
|
|
11
11
|
{ "rule": "sample#4", "group": "样例·状态列", "sid": "admin.content.table.cell_status", "dims": ["form", "bg"], "channel": ["form", "structure_ops"], "source": "spec", "always": true },
|
package/parser/index.js
CHANGED
|
@@ -395,12 +395,16 @@ function matchOne(file, dataset, batchSummary, opts = {}) {
|
|
|
395
395
|
// oracle 验收基线(:设计侧给的效果图 + 待比对点位;项目侧落地后跑 verify 逐点 diff)
|
|
396
396
|
// mockup 相对路径解析以「变更集同目录」为第一基准(协议约定 oracle 产物与变更集同目录),
|
|
397
397
|
// 其次 cwd / 技能根(历史行为兼容)。
|
|
398
|
-
|
|
398
|
+
// G11 oracle 基线闸:restore 模式下返回值非 0 = 阻断(与 G8 同级)
|
|
399
|
+
const oracleGaps = checkOracle(changeset, plan, valueDict, { strict: mode === "restore", filePath: file }) || 0;
|
|
399
400
|
checkCoverage(changeset, { strict: mode === "restore" });
|
|
400
401
|
// 登记表覆盖率(子项级细闸):以登记表为权威、当场重算 A/C,设计侧自报的 coverage 不参与
|
|
401
|
-
|
|
402
|
+
// strict(mode=restore)同时驱动 G9 登记表身份闸与 G10 dims 兑现闸
|
|
403
|
+
const regGaps = checkRegistryCoverage(changeset, plan, { ...opts, strict: mode === "restore" });
|
|
402
404
|
if (batchSummary)
|
|
403
|
-
batchSummary.registryGaps += regGaps;
|
|
405
|
+
batchSummary.registryGaps += regGaps + oracleGaps;
|
|
406
|
+
else if (regGaps + oracleGaps > 0)
|
|
407
|
+
process.exitCode = 1;
|
|
404
408
|
|
|
405
409
|
// 输出转换计划
|
|
406
410
|
console.log(`\n=== 三级匹配结果(scene=${changeset.scene},${plan.length} 条)===`);
|
|
@@ -735,11 +739,12 @@ function priorityRequirement(strategy) {
|
|
|
735
739
|
function checkOracle(changeset, plan, valueDict, opts = {}) {
|
|
736
740
|
const oracle = changeset.oracle;
|
|
737
741
|
if (!oracle || typeof oracle !== "object") {
|
|
738
|
-
if (opts.strict)
|
|
742
|
+
if (opts.strict) {
|
|
739
743
|
console.error(`\n✖ mode=restore 下 oracle 缺失(G8 模式闸要求,见变更集校验段)——基线三件套不完整,先回设计侧补齐。`);
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
744
|
+
return 1; // G11:restore 下基线缺失 = 阻断,不再是提示后继续
|
|
745
|
+
}
|
|
746
|
+
console.log(`\n提示:变更集未提供 oracle 验收基线(场景还原应给)—— 落地后无法做 computed style 逐点比对,还原度不可证明,建议回流设计侧补齐。`);
|
|
747
|
+
return 0;
|
|
743
748
|
}
|
|
744
749
|
|
|
745
750
|
const sids = Array.isArray(oracle.sids) ? oracle.sids : [];
|
|
@@ -819,11 +824,22 @@ function checkOracle(changeset, plan, valueDict, opts = {}) {
|
|
|
819
824
|
|
|
820
825
|
if (issues.length === 0) {
|
|
821
826
|
console.log(` ✔ oracle 校验通过:主题一致、覆盖度双向闭合`);
|
|
822
|
-
return;
|
|
827
|
+
return 0;
|
|
828
|
+
}
|
|
829
|
+
// G11 oracle 基线硬闸(2026-09-21 机制化):restore 模式下基线问题从「⚠ 软提示」升格为阻断。
|
|
830
|
+
// 历史缺口:主题错配 / 欠声明 / 无基线只打 ⚠ 就继续——基线断了仍绿灯交付,
|
|
831
|
+
// verify 无从做 1:1 证明,「细节没还原到位」在交付时不可见。
|
|
832
|
+
if (opts.strict) {
|
|
833
|
+
console.error(`\n✖ oracle 基线问题(G11 · ${issues.length} 类 → 拒绝执行):`);
|
|
834
|
+
for (const it of issues)
|
|
835
|
+
console.error(` ✘ ${it}`);
|
|
836
|
+
console.error(` 处置:按上列各条回设计侧补齐基线(换本主题效果图 / 补 sids 声明 / 声明 theme_mapping 同构异色复用)后重跑。`);
|
|
837
|
+
return 1;
|
|
823
838
|
}
|
|
824
839
|
console.log(`\n⚠ oracle 基线问题(${issues.length} 类):`);
|
|
825
840
|
for (const it of issues)
|
|
826
841
|
console.log(` ✘ ${it}`);
|
|
842
|
+
return 0;
|
|
827
843
|
}
|
|
828
844
|
|
|
829
845
|
/**
|
|
@@ -867,7 +883,7 @@ function checkCoverage(changeset, opts = {}) {
|
|
|
867
883
|
console.log(` ✘ ${it}`);
|
|
868
884
|
}
|
|
869
885
|
|
|
870
|
-
/** 依次尝试候选路径,返回首个存在者(相对路径基准:变更集所在目录 → 当前工作目录 →
|
|
886
|
+
/** 依次尝试候选路径,返回首个存在者(相对路径基准:变更集所在目录 → 当前工作目录 → 技能仓库根 → 兄弟设计技能 project-ui-design 根) */
|
|
871
887
|
function resolveFirstExisting(raw, filePath) {
|
|
872
888
|
if (!raw || typeof raw !== "string")
|
|
873
889
|
return null;
|
|
@@ -877,6 +893,10 @@ function resolveFirstExisting(raw, filePath) {
|
|
|
877
893
|
if (filePath)
|
|
878
894
|
bases.push(path.dirname(filePath));
|
|
879
895
|
bases.push(process.cwd(), ROOT);
|
|
896
|
+
// 兄弟技能根:真实设计侧登记表/效果图沉淀在 project-ui-design(设计侧 page-specs),
|
|
897
|
+
// 跨库引用时允许相对该根解析(两侧技能目录同级部署是标准布局)。
|
|
898
|
+
const sibling = path.resolve(ROOT, "..", "project-ui-design");
|
|
899
|
+
bases.push(sibling);
|
|
880
900
|
for (const base of bases) {
|
|
881
901
|
const candidate = path.resolve(base, raw);
|
|
882
902
|
if (existsSync(candidate))
|
|
@@ -919,6 +939,12 @@ function checkRegistryCoverage(changeset, plan, opts = {}) {
|
|
|
919
939
|
console.error(`\n✖ 登记表文件不存在:${opts.registryArg}`);
|
|
920
940
|
return 1;
|
|
921
941
|
}
|
|
942
|
+
if (opts.strict) {
|
|
943
|
+
// G9 前置缺口:mode=restore 却解析不到登记表实物(G8 只验了字符串非空)
|
|
944
|
+
console.error(`\n✖ G9 登记表身份闸:mode=restore 但登记表实物不存在(coverage.registry="${raw}" 解析失败)→ 拒绝执行。`);
|
|
945
|
+
console.error(` 覆盖率分母必须来自「方案 × 场景」的真实登记表,否则壳层/表格细粒度点位从分母消失,欠声明不可数。`);
|
|
946
|
+
return 1;
|
|
947
|
+
}
|
|
922
948
|
console.log(`\n提示:未提供登记表(--registry 或 coverage.registry)—— 组级台账只防「整组忘光」,组内子项被静默丢失无法计数,建议场景还原带登记表。`);
|
|
923
949
|
return 0;
|
|
924
950
|
}
|
|
@@ -931,6 +957,23 @@ function checkRegistryCoverage(changeset, plan, opts = {}) {
|
|
|
931
957
|
console.error(`\n✖ 登记表读取/解析失败:${registryPath} —— ${e.message}`);
|
|
932
958
|
return 1;
|
|
933
959
|
}
|
|
960
|
+
|
|
961
|
+
// G9 登记表身份闸(2026-09-21 机制化):restore 模式下,登记表必须属于「本变更集声明的方案 × 场景」,
|
|
962
|
+
// 且必须是有 items 的真登记表。历史缺口:G8 只验 coverage.registry 是非空字符串——
|
|
963
|
+
// 拿 6 条的回归夹具 registry-sample.json、甚至别的方案/场景的登记表都能过 G8,
|
|
964
|
+
// 覆盖率分母(R=186 的壳层+表格子项)被偷换成小表,「面包屑/顶栏图标/表头 nowrap」这类点位
|
|
965
|
+
// 从分母里消失 → 欠声明不可数 → 细节还原缺口一路绿灯。凡「身份对不上的表」视同没有表。
|
|
966
|
+
const scheme = typeof changeset.scheme === "string" ? changeset.scheme : "";
|
|
967
|
+
const scene = typeof changeset.scene === "string" ? changeset.scene : "";
|
|
968
|
+
const regScheme = typeof registry.design_scheme === "string" ? registry.design_scheme : "";
|
|
969
|
+
const regScene = typeof registry.scene === "string" ? registry.scene : "";
|
|
970
|
+
const identityMismatch = (regScheme && scheme && regScheme !== scheme) || (regScene && scene && regScene !== scene);
|
|
971
|
+
if (opts.strict && (identityMismatch || !regScheme || !regScene)) {
|
|
972
|
+
console.error(`\n✖ G9 登记表身份闸:登记表 ${path.basename(registryPath)} 属于 scheme="${regScheme || "?"}"/scene="${regScene || "?"}",与变更集 scheme="${scheme || "?"}"/scene="${scene || "?"}" 不一致(或缺身份字段)→ 拒绝执行。`);
|
|
973
|
+
console.error(` 处置:coverage.registry 改指「${scheme} × ${scene}」方案的登记表(如设计侧 page-specs/styles/<方案>/scenes/<场景>/restore-registry.json)。`);
|
|
974
|
+
return 1;
|
|
975
|
+
}
|
|
976
|
+
|
|
934
977
|
const items = Array.isArray(registry.items) ? registry.items : [];
|
|
935
978
|
if (items.length === 0) {
|
|
936
979
|
console.error(`\n✖ 登记表不含 items:${registryPath}`);
|
|
@@ -972,11 +1015,56 @@ function checkRegistryCoverage(changeset, plan, opts = {}) {
|
|
|
972
1015
|
const mockupSids = physicalSids || declaredSids;
|
|
973
1016
|
|
|
974
1017
|
const applicable = items.filter(it => it.always === true || registrySids(it).some(s => mockupSids.has(s)));
|
|
975
|
-
|
|
1018
|
+
|
|
1019
|
+
// G10 dims 兑现闸(2026-09-21 机制化):「兑现」从「ID 出现」升格为「ID 出现 且 dims 维度全部出现」。
|
|
1020
|
+
// 历史缺口:只数 ID——声明了 admin.content.table.header_cell 却漏掉 nowrap / font_weight /
|
|
1021
|
+
// text_align 等关键维度也算「已兑现」→ 表头竖排(nowrap 丢失)、字重不对(font_weight 丢失)
|
|
1022
|
+
// 这类「点位在、细节丢」的症状一路绿灯。核对口径:dims 中的 form 看 change.form;
|
|
1023
|
+
// 其余维度看 change.style ∪ change.layer 的键;source:none(登记即兑现)、global 伪点位
|
|
1024
|
+
// (全局通道字段名与登记 dims 不同构)、visible:false 隐藏点位不做 dims 机检。
|
|
1025
|
+
const hiddenIds = new Set((changeset.changes || []).filter(c => c && c.visible === false).map(c => c.id));
|
|
1026
|
+
const missingDimsOf = (it, change) => {
|
|
1027
|
+
const dims = it.dims || [];
|
|
1028
|
+
const styleKeys = new Set([...Object.keys(change.style || {}), ...Object.keys(change.layer || {})]);
|
|
1029
|
+
const missing = [];
|
|
1030
|
+
if (dims.includes("form") && change.form === undefined)
|
|
1031
|
+
missing.push("form");
|
|
1032
|
+
for (const d of dims.filter(d => d !== "form")) {
|
|
1033
|
+
if (!styleKeys.has(d))
|
|
1034
|
+
missing.push(d);
|
|
1035
|
+
}
|
|
1036
|
+
return missing;
|
|
1037
|
+
};
|
|
1038
|
+
const dimsGaps = []; // { item, missing }
|
|
1039
|
+
const gaps = applicable.filter(it => {
|
|
1040
|
+
const sids = registrySids(it);
|
|
1041
|
+
if (!sids.every(s => declared.has(s)))
|
|
1042
|
+
return true; // ID 级欠声明(原有缺口口径)
|
|
1043
|
+
if (it.source === "none")
|
|
1044
|
+
return false;
|
|
1045
|
+
const primary = sids.find(s => s !== GLOBAL_PSEUDO_ID);
|
|
1046
|
+
if (!primary)
|
|
1047
|
+
return false; // global 伪点位条目
|
|
1048
|
+
if (hiddenIds.has(primary))
|
|
1049
|
+
return false; // visible:false 点位 dims 豁免(与 oracle 隐藏点位豁免同口径)
|
|
1050
|
+
const change = (changeset.changes || []).find(c => c.id === primary);
|
|
1051
|
+
if (!change)
|
|
1052
|
+
return false; // 经 pending/visible 兑现且无 style 意图条目 → dims 由台账人工闸承载
|
|
1053
|
+
const missing = missingDimsOf(it, change);
|
|
1054
|
+
if (missing.length === 0)
|
|
1055
|
+
return false;
|
|
1056
|
+
dimsGaps.push({ item: it, missing });
|
|
1057
|
+
return false;
|
|
1058
|
+
});
|
|
976
1059
|
|
|
977
1060
|
console.log(`\n=== 登记表覆盖率(子项级细闸 · 当场重算)===`);
|
|
978
1061
|
console.log(` 登记表:${registryPath}(登记项 R=${items.length})`);
|
|
979
|
-
console.log(` 适用 A=${applicable.length} / 已兑现 C=${applicable.length - gaps.length} / 缺口 ${gaps.length}`);
|
|
1062
|
+
console.log(` 适用 A=${applicable.length} / 已兑现 C=${applicable.length - gaps.length} / 缺口 ${gaps.length}${dimsGaps.length > 0 ? ` / dims 缺口 ${dimsGaps.length}(G10)` : ""}`);
|
|
1063
|
+
if (dimsGaps.length > 0) {
|
|
1064
|
+
console.log(` ⚠ dims 兑现缺口 ${dimsGaps.length} 条(ID 已声明、dims 维度未给全):`);
|
|
1065
|
+
for (const { item, missing } of dimsGaps.slice(0, 10))
|
|
1066
|
+
console.log(` ${item.rule} ${registrySids(item).join(" + ")} 缺 dims=[${missing.join(",")}]`);
|
|
1067
|
+
}
|
|
980
1068
|
|
|
981
1069
|
// 实物校验:标注缺口的权威来源是效果图 HTML 里的 data-sid,而不是自报的 oracle.sids
|
|
982
1070
|
let physicalGap = false;
|
|
@@ -1008,34 +1096,44 @@ function checkRegistryCoverage(changeset, plan, opts = {}) {
|
|
|
1008
1096
|
physicalGap = true;
|
|
1009
1097
|
}
|
|
1010
1098
|
|
|
1011
|
-
if (gaps.length === 0 && !physicalGap) {
|
|
1012
|
-
console.log(` ✔ 覆盖率通过:C = A
|
|
1099
|
+
if (gaps.length === 0 && dimsGaps.length === 0 && !physicalGap) {
|
|
1100
|
+
console.log(` ✔ 覆盖率通过:C = A,无子项被静默丢失;dims 维度全兑现(G10);效果图实物标注闭合`);
|
|
1013
1101
|
return 0;
|
|
1014
1102
|
}
|
|
1015
1103
|
|
|
1016
|
-
if (gaps.length === 0 && physicalGap) {
|
|
1104
|
+
if (gaps.length === 0 && dimsGaps.length === 0 && physicalGap) {
|
|
1017
1105
|
console.log(`\n✘ 效果图实物标注不闭合 → exit 1(oracle.sids 与效果图 HTML 的 data-sid 不一致 / 恒存在子项缺标注)`);
|
|
1018
1106
|
console.log(` 处置:给效果图对应元素补 data-sid,或把该登记项降级 source: spec(见 mockup-extraction-spec.md §7)`);
|
|
1019
1107
|
return 1;
|
|
1020
1108
|
}
|
|
1021
1109
|
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
byGroup.get(g).push(it);
|
|
1110
|
+
if (dimsGaps.length > 0 && opts.strict) {
|
|
1111
|
+
console.log(`\n✘ dims 兑现缺口(G10 · ID 已声明但 dims 维度未给全,共 ${dimsGaps.length} 条 → exit 1):`);
|
|
1112
|
+
for (const { item, missing } of dimsGaps)
|
|
1113
|
+
console.log(` ${item.rule} ${registrySids(item).join(" + ")} 缺 dims=[${missing.join(",")}]`);
|
|
1114
|
+
console.log(` 处置:在对应 changes[] 条目的 style/layer 补齐所缺维度取值(值来源见 source 字段);「点位在、细节丢」正是样式细节不还原的机制成因。`);
|
|
1028
1115
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
const
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1116
|
+
|
|
1117
|
+
if (gaps.length > 0) {
|
|
1118
|
+
const byGroup = new Map();
|
|
1119
|
+
for (const it of gaps) {
|
|
1120
|
+
const g = it.group || "(未分组)";
|
|
1121
|
+
if (!byGroup.has(g))
|
|
1122
|
+
byGroup.set(g, []);
|
|
1123
|
+
byGroup.get(g).push(it);
|
|
1124
|
+
}
|
|
1125
|
+
console.log(`\n✘ 登记表覆盖率缺口(子项级欠声明,共 ${gaps.length} 条 → exit 1):`);
|
|
1126
|
+
for (const [group, list] of byGroup) {
|
|
1127
|
+
console.log(` · ${group}(${list.length})`);
|
|
1128
|
+
const shown = opts.verbose ? list : list.slice(0, 6);
|
|
1129
|
+
for (const it of shown)
|
|
1130
|
+
console.log(` ${it.rule} ${registrySids(it).join(" + ")} [${(it.dims || []).join(",")}]`);
|
|
1131
|
+
if (!opts.verbose && list.length > shown.length)
|
|
1132
|
+
console.log(` …(同组其余 ${list.length - shown.length} 条,加 --verbose 展开)`);
|
|
1133
|
+
}
|
|
1037
1134
|
}
|
|
1038
|
-
|
|
1135
|
+
// G10 dims 缺口计入返回值:strict 模式下 =「交付不完整」与欠声明同级
|
|
1136
|
+
return gaps.length + (opts.strict ? dimsGaps.length : 0);
|
|
1039
1137
|
}
|
|
1040
1138
|
|
|
1041
1139
|
/**
|
package/parser/regression.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* A-
|
|
4
|
+
* A-T 端到端一键回归(作者侧维护工具,不随技能分发)
|
|
5
5
|
*
|
|
6
6
|
* 用法(cwd 任意,脚本内部已固定为 skill 根目录执行):
|
|
7
7
|
* node parser/regression.js
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
* H match 整页场景还原样例(mode=restore)→ exit 0 且输出含 #245BFF 与「G8 模式闸」(壳层+内容区全模块 L1)
|
|
19
19
|
* P match G8 负例(mode=restore 缺 oracle/coverage)→ exit 1 且输出含「G8 模式闸」(伪还原变更集拦截)
|
|
20
20
|
* Q match G8 强化负例(mode=restore 但 mockup/registry 为空壳)→ exit 1 且输出含「G8 模式闸」(有壳无芯伪基线拦截)
|
|
21
|
+
* R match G9 负例(scheme=tangerine 却引 default 方案登记表 = 身份错配)→ exit 1 且输出含「G9 登记表身份闸」(分母偷换拦截)
|
|
22
|
+
* S match G10 负例(header_cell ID 已声明但缺 text_align/nowrap 维度)→ exit 1 且输出含「G10」与「缺 dims=」(点位在细节丢拦截)
|
|
23
|
+
* T match G11 负例(橘橙主色配钴蓝效果图且无 theme_mapping = 主题错配)→ exit 1 且输出含「G11」与「主题错配」(基线断裂拦截)
|
|
21
24
|
* I build --dry 产物链自检 → exit 0 且输出含 dry-run
|
|
22
25
|
* J match 三声明维度 → exit 0 且输出含「结构施工 structure_ops」
|
|
23
26
|
* K audit 挂载点 / 死通道审计 → exit 1(夹具项目故意存在挂载点缺失 / 死通道)
|
|
@@ -168,12 +171,33 @@ const steps = [
|
|
|
168
171
|
args: ["match", path.join(FIXTURES, "changeset-neg5-g8-stub.json")],
|
|
169
172
|
expect: { code: 1, includes: "G8 模式闸" },
|
|
170
173
|
},
|
|
174
|
+
{
|
|
175
|
+
key: "R",
|
|
176
|
+
name: "match G9 负例(scheme=tangerine 却引 default 方案登记表 = 身份错配 → exit 1)",
|
|
177
|
+
script: INDEX,
|
|
178
|
+
args: ["match", path.join(FIXTURES, "changeset-neg6-g9-identity.json")],
|
|
179
|
+
expect: { code: 1, includes: "G9 登记表身份闸" },
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
key: "S",
|
|
183
|
+
name: "match G10 负例(header_cell ID 已声明但缺 text_align/nowrap 维度 = 点位在细节丢 → exit 1)",
|
|
184
|
+
script: INDEX,
|
|
185
|
+
args: ["match", path.join(FIXTURES, "changeset-neg7-g10-dims.json")],
|
|
186
|
+
expect: { code: 1, includes: ["G10", "缺 dims="] },
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
key: "T",
|
|
190
|
+
name: "match G11 负例(橘橙主色配钴蓝效果图且无 theme_mapping = 主题错配 → exit 1)",
|
|
191
|
+
script: INDEX,
|
|
192
|
+
args: ["match", path.join(FIXTURES, "changeset-neg8-g11-oracle.json")],
|
|
193
|
+
expect: { code: 1, includes: ["G11", "主题错配"] },
|
|
194
|
+
},
|
|
171
195
|
];
|
|
172
196
|
|
|
173
197
|
const results = [];
|
|
174
198
|
let failed = 0;
|
|
175
199
|
|
|
176
|
-
console.log("=== A-
|
|
200
|
+
console.log("=== A-T 端到端一键回归 ===\n");
|
|
177
201
|
|
|
178
202
|
for (const step of steps) {
|
|
179
203
|
const { status, stdout, stderr } = spawnSync(
|
|
@@ -210,4 +234,4 @@ if (failed > 0) {
|
|
|
210
234
|
console.error(`\n✖ ${failed} 步未通过,见上方详情`);
|
|
211
235
|
process.exit(1);
|
|
212
236
|
}
|
|
213
|
-
console.log("\n✔ A-
|
|
237
|
+
console.log("\n✔ A-T 全部通过,mapping/parser 可提交或发版");
|
|
@@ -193,10 +193,13 @@ node parser/index.js match --batch <changesets-dir>
|
|
|
193
193
|
| 闸 | 触发条件 | 判据来源 | 违规输出 |
|
|
194
194
|
|---|---|---|---|
|
|
195
195
|
| **G8 模式闸** | 变更集顶层 `mode: "restore"`(场景还原)但基线不全:缺 `scheme` / `oracle` / `coverage`,**或 `oracle.mockup` / `coverage.registry` 为空**(有壳无芯的伪基线)——伪还原变更集(只换主题色却以还原之名交付)拒绝执行;`mode` 非法值同样阻断 | 变更集顶层 `scheme` / `mode` / `oracle.mockup` / `coverage.registry` | `G8 模式闸:mode=restore 但缺少 … → 拒绝执行` |
|
|
196
|
+
| **G9 登记表身份闸** | `mode=restore` 但登记表**身份对不上**:`coverage.registry` 实物解析失败,或登记表 `design_scheme`/`scene` 与变更集 `scheme`/`scene` 不一致(或缺身份字段)——凡身份对不上的表视同没有表,防止覆盖率分母被偷换(面包屑/顶栏图标/表头 nowrap 等点位从分母消失,欠声明不可数) | 登记表顶层 `design_scheme` / `scene` ↔ 变更集顶层 `scheme` / `scene` | `G9 登记表身份闸:登记表 … 属于 scheme="…"/scene="…",与变更集 … 不一致 → 拒绝执行` |
|
|
197
|
+
| **G10 dims 兑现闸** | `mode=restore` 下登记项的 ID 已在 `changes[]` 声明,但登记 `dims` 维度未全部给全(`form` 看 `change.form`,其余看 `style ∪ layer` 的键;`source:none`、global 伪点位、`visible:false` 豁免)——「点位在、细节丢」(表头竖排 = nowrap 丢失)正是样式细节不还原的机制成因,dims 缺口与欠声明同级阻断 | 登记表条目 `dims` ↔ 变更集条目 `form` / `style` / `layer` | `dims 兑现缺口(G10 · … 条 → exit 1):… 缺 dims=[…]` |
|
|
198
|
+
| **G11 oracle 基线闸** | `mode=restore` 下 oracle 校验发现问题(主题错配 / `oracle.sids` 欠声明或无基线 / 实物缺口):restore 下从「⚠ 软提示继续」升格为「拒绝执行」——基线断了仍绿灯交付,verify 无从做 1:1 证明。同构异色复用须在 oracle 显式声明 `theme_mapping: { from, to }` | oracle 主题词 ↔ `global.brand_primary` 主题词;`oracle.sids` ↔ `changes[].id` 双向 | `oracle 基线问题(G11 · … 类 → 拒绝执行):主题错配 …` |
|
|
196
199
|
| **G1 suppress 收口** | 条目声明某 `form`,词典 `suppress_rules[form]`(或 forms 描述「suppress 必含 x」内联标记)要求收口的出厂互斥通道未全部出现在该条目 `suppress[]` | 词典条目 `suppress_rules` | `suppress 缺口:…必须收口出厂互斥通道 [x],缺 [x]` |
|
|
197
200
|
| **G5 几何语境** | 词典 preconditions 含「几何语境随值迁移」标记 ∧ `style` 含 padding/margin 族几何字段落宿主 ∧ 未声明 `suppress_inner` | 词典条目 preconditions 标记句 | `suppress_inner 缺口:…两层之和 ≠ 设计值` |
|
|
198
201
|
|
|
199
|
-
三闸与禁词校验同级阻断(`exit 1`)——「新旧形态叠加」「两层 padding 相加」「伪还原只换主题」都是历史事故源(双竖条、28px 列挤压、「还原后布局细节零变化」),不允许靠观感兜底。G8 判据一句话:**「把系统 / 页面改成 X」默认是还原(restore),必须带齐 `scheme` + `oracle.mockup` + `coverage.registry`;只有「显式声明只改主题色、其它不动」才用 `design`**(2026-09-20 事故机制化:还原项目后重跑,无登记表无基线的轻量变更集一路绿灯,落地后「只变了主题、布局细节零变化」;二轮强化再堵住 `oracle`/`coverage` 只给空壳、无 `mockup`/`registry` 芯的写法)。**降级不许静默发生**:变更集 `notes` 与交付说明都须显式写出本次 `mode` 与范围。
|
|
202
|
+
三闸与禁词校验同级阻断(`exit 1`)——「新旧形态叠加」「两层 padding 相加」「伪还原只换主题」都是历史事故源(双竖条、28px 列挤压、「还原后布局细节零变化」),不允许靠观感兜底。G8 判据一句话:**「把系统 / 页面改成 X」默认是还原(restore),必须带齐 `scheme` + `oracle.mockup` + `coverage.registry`;只有「显式声明只改主题色、其它不动」才用 `design`**(2026-09-20 事故机制化:还原项目后重跑,无登记表无基线的轻量变更集一路绿灯,落地后「只变了主题、布局细节零变化」;二轮强化再堵住 `oracle`/`coverage` 只给空壳、无 `mockup`/`registry` 芯的写法)。**降级不许静默发生**:变更集 `notes` 与交付说明都须显式写出本次 `mode` 与范围。restore 模式下 G9/G10/G11 同时生效(登记表身份、dims 维度兑现、oracle 基线三道复闸),三者判据细节见上表与「登记表覆盖率」小节。
|
|
200
203
|
|
|
201
204
|
**验收基线输出**:转换计划末尾另打印 `=== 验收基线 oracle ===`(效果图路径 + 待比对点位)与 `=== 覆盖率 coverage ===`(登记项 R / 适用 A / 已兑现 C)。有 `oracle` → 落地后必须跑第 6 步 `verify`;缺 `oracle` / `coverage` → 输出提示,把「补基线 / 补登记覆盖率」回流设计侧(场景还原应给)。
|
|
202
205
|
**覆盖率校验**:`coverage.covered` 必须等于 `coverage.applicable`、`gaps` 为空,否则打印缺口清单——`C < A` 即**欠声明**(有规范子项未落进 `changes[]`/`visible`/`pending`),属设计侧交付不完整,必须回流,不得在项目侧"猜着补"。
|
|
@@ -523,9 +526,12 @@ node parser/index.js registry parser/fixtures/registry-sample.json # N. 登
|
|
|
523
526
|
node parser/index.js registry parser/fixtures/registry-bad.json # O. 登记表硬缺口:引用不存在且未标 pending 的点位 → exit 1
|
|
524
527
|
node parser/index.js match parser/fixtures/changeset-neg4-g8.json # P. G8 模式闸负例:mode=restore 缺 oracle/coverage(伪还原变更集)→ exit 1
|
|
525
528
|
node parser/index.js match parser/fixtures/changeset-neg5-g8-stub.json # Q. G8 强化负例:mode=restore 但 mockup/registry 空壳(有壳无芯伪基线)→ exit 1
|
|
529
|
+
node parser/index.js match parser/fixtures/changeset-neg6-g9-identity.json # R. G9 身份闸负例:scheme=tangerine 却引 default 方案登记表(分母偷换)→ exit 1
|
|
530
|
+
node parser/index.js match parser/fixtures/changeset-neg7-g10-dims.json # S. G10 dims 闸负例:header_cell 缺 text_align/nowrap(点位在细节丢)→ exit 1
|
|
531
|
+
node parser/index.js match parser/fixtures/changeset-neg8-g11-oracle.json # T. G11 oracle 闸负例:橘橙主色配钴蓝效果图且无 theme_mapping(主题错配)→ exit 1
|
|
526
532
|
```
|
|
527
533
|
|
|
528
|
-
通过标准:regression.js 输出 `A✔ B✔ …
|
|
534
|
+
通过标准:regression.js 输出 `A✔ B✔ … T✔` 且 exit 0;分步跑时各步符合注释预期。夹具含义见各文件 `$comment`。
|
|
529
535
|
|
|
530
536
|
## 配套工具(作者/维护侧)
|
|
531
537
|
|