Archived
ACT-WORK-05:标准化参数集改子表 parts.parameter,与目标件页面结构对齐
用户核对实跑页面后指出:P-08 数据工单做出来的页面结构必须与目标件 《数据工单-01-芯片主数据创建》一致——目标件本就是两张表(表 1 主记录 / 表 2 标准化参数子表),而实现把参数集塞成了表 1 的一个文本列,违反 《SS02-SS03-SS04_Demo台账字段细化与统一方案》§六「重复明细用子表承载, 不在单一文本字段堆叠」。 五处联动改齐: - 平台基线新增 parts.parameter 主数据表(内部料号+参数名复合主键), 两颗样例料的参数集从 normalized_parameter_set 文本列拆成 7 行子表数据 (数值原样搬,一个字未改);parts.profile 物理列保留、不再赋值。 - 活动清单:parts.profile 撤掉该字段声明,新增 parts.parameter 声明 (internal_pn 引用墙、param_value/constraint_type 必填);版本号 1.1.1 → 1.2.0。 - 案例模型:S0d_p08_master/S1_input_confirm/S2_normalize 的读写面与 guide 全部改指向新子表;顺带修正候选计数措辞歧义(实测样例0一张该发 的决策卡被跳过——"候选absent且候选数≥2"被模型读成"不在库的候选≥2颗", 改成先分别数"候选总数"与"不在库的候选数"两个数、显式说清楚判据认哪个)。 - caseFileModel 补 parts_parameter_missing 读数,两条哨兵(s_p08_created / s_pns_resolved)一并要求这一列不缺必填。 - 报告模版补齐表 2(逐块搬自目标件),主键列挂 data-col,约束类型走 data-class-of 徽标。 - e2e 套件加性支持"一张卡填两张表"(stage.extraTables),buildEdits 的 rowKey 泛化支持复合主键数组形态(不破坏既有八套件)。 验证:vitest 413 passed(活动包+平台种子测试全绿)、typecheck/lint/ depcruise 三绿、activities:install 零静态审发现、SQL 核对 parts.parameter 主键与行数(两颗料各7行)。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FJcX8A6TWp4GRs41TYryEh
This commit is contained in:
@@ -76,11 +76,17 @@ describe('清单本身合规', () => {
|
||||
});
|
||||
|
||||
describe('台账声明:授权面与《统一方案》口径', () => {
|
||||
it('P-08 一张表:主键 internal_pn,参数集是它的一个必填字段,没有 parts.parameter 子表', () => {
|
||||
it('P-08 主键 internal_pn,标准化参数集拆成独立子表 parts.parameter(2026-08-27 结构改:与目标件一致)', () => {
|
||||
const p08 = byAddress('parts', 'profile');
|
||||
expect(p08?.fields.filter((f) => f.primaryKey).map((f) => f.name)).toEqual(['internal_pn']);
|
||||
expect(p08?.fields.find((f) => f.name === 'normalized_parameter_set')?.required).toBe(true);
|
||||
expect(byAddress('parts', 'parameter')).toBeUndefined();
|
||||
expect(p08?.fields.find((f) => f.name === 'normalized_parameter_set')).toBeUndefined();
|
||||
const param = byAddress('parts', 'parameter');
|
||||
expect(param?.kind).toBe('master');
|
||||
expect(param?.fields.filter((f) => f.primaryKey).map((f) => f.name)).toEqual(['internal_pn', 'param_name']);
|
||||
expect(param?.fields.find((f) => f.name === 'internal_pn')?.refersTo).toBe('parts.profile.internal_pn');
|
||||
expect(param?.fields.find((f) => f.name === 'param_value')?.required).toBe(true);
|
||||
expect(param?.fields.find((f) => f.name === 'constraint_type')?.tally).toEqual(['hard', 'soft']);
|
||||
expect(param?.fields.find((f) => f.name === 'constraint_type')?.required).toBe(true);
|
||||
});
|
||||
|
||||
it('P-11 主记录的原 PN / 候选 PN 都是引用墙(查无此料当场拒 —— 存在性检查的硬门)', () => {
|
||||
@@ -186,12 +192,16 @@ describe('案例模型与清单的对齐', () => {
|
||||
});
|
||||
|
||||
describe('报告模版:编辑面与只读面各就各位', () => {
|
||||
it('两张数据工单件可加行可编辑:data-edit / data-edit-add 与主键 data-col 都在', () => {
|
||||
it('P-08 数据工单件的表 1 + 表 2(标准化参数子表)都可加行可编辑:data-edit / data-edit-add 与主键 data-col 都在', () => {
|
||||
const p08 = viewHtml('p08-master-create');
|
||||
expect(p08).toContain('data-edit="parts.profile"');
|
||||
expect(p08).toContain('data-edit-add="parts.profile"');
|
||||
expect(p08).toContain('data-col="internal_pn"');
|
||||
expect(p08).toContain('data-col="normalized_parameter_set"');
|
||||
expect(p08).toContain('data-edit="parts.parameter"');
|
||||
expect(p08).toContain('data-edit-add="parts.parameter"');
|
||||
expect(p08).toContain('data-col="param_name"');
|
||||
expect(p08).toContain('data-col="param_value"');
|
||||
expect(p08).toContain('data-col="constraint_type"');
|
||||
const p10 = viewHtml('p10-document-create');
|
||||
expect(p10).toContain('data-edit="parts.document"');
|
||||
expect(p10).toContain('data-col="doc_seq"');
|
||||
@@ -211,15 +221,15 @@ describe('报告模版:编辑面与只读面各就各位', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('每个可编辑格子的 data-col 都在对应台账对象的声明里', () => {
|
||||
const cases: Array<[string, string, string]> = [
|
||||
['p08-master-create', 'parts', 'profile'],
|
||||
['p10-document-create', 'parts', 'document'],
|
||||
['eval-input-list', D, 'input_gap'],
|
||||
it('每个可编辑格子的 data-col 都在对应台账对象的声明里(p08-master-create 一屏两张表,两张台账对象的声明并起来看)', () => {
|
||||
const cases: Array<[string, Array<[string, string]>]> = [
|
||||
['p08-master-create', [['parts', 'profile'], ['parts', 'parameter']]],
|
||||
['p10-document-create', [['parts', 'document']]],
|
||||
['eval-input-list', [[D, 'input_gap']]],
|
||||
];
|
||||
for (const [view, domain, object] of cases) {
|
||||
for (const [view, objects] of cases) {
|
||||
const cols = new Set([...viewHtml(view).matchAll(/data-col="([^"]+)"/g)].map((m) => m[1] ?? ''));
|
||||
const declared = new Set(byAddress(domain, object)?.fields.map((f) => f.name));
|
||||
const declared = new Set(objects.flatMap(([domain, object]) => byAddress(domain, object)?.fields.map((f) => f.name) ?? []));
|
||||
for (const c of cols) expect(declared.has(c), `${view}: ${c}`).toBe(true);
|
||||
}
|
||||
});
|
||||
@@ -268,6 +278,7 @@ describe('徽标别名与值域相关的坑(2026-08-27 实测账,回归网)', ()
|
||||
/** 每张模版真的摆了徽标的那几列(带下划线的 tally 值最容易漏,漏了就是「待定」那次事故) */
|
||||
const BADGED: ReadonlyArray<{ view: string; domain: string; object: string; column: string }> = [
|
||||
{ view: 'p08-master-create', domain: 'parts', object: 'profile', column: 'lifecycle_status' },
|
||||
{ view: 'p08-master-create', domain: 'parts', object: 'parameter', column: 'constraint_type' },
|
||||
{ view: 'p10-document-create', domain: 'parts', object: 'document', column: 'document_type' },
|
||||
{ view: 'p10-document-create', domain: 'parts', object: 'document', column: 'document_status' },
|
||||
{ view: 'eval-input-list', domain: D, object: 'pn_check', column: 'exists_status' },
|
||||
@@ -319,6 +330,7 @@ describe('可编辑件的主键与必填列(2026-08-27 复审:主键丢钥匙 /
|
||||
/** 三张真能编辑的件与它们各自绑定的台账对象 */
|
||||
const EDITABLE: ReadonlyArray<{ view: string; domain: string; object: string }> = [
|
||||
{ view: 'p08-master-create', domain: 'parts', object: 'profile' },
|
||||
{ view: 'p08-master-create', domain: 'parts', object: 'parameter' },
|
||||
{ view: 'p10-document-create', domain: 'parts', object: 'document' },
|
||||
{ view: 'eval-input-list', domain: D, object: 'input_gap' },
|
||||
];
|
||||
|
||||
@@ -154,13 +154,22 @@ describe('说明书与剧本的骨架', () => {
|
||||
expect(s3).toContain('工具调用后同拍其余动作作废');
|
||||
});
|
||||
|
||||
it('S0 剧本写明都在库时数据工单两项本就不会进「当下可为」;S0d_p08_master 剧本写明候选 ≥2 才问、=1 必建、原 PN 硬阻塞', () => {
|
||||
it('S0 剧本写明都在库时数据工单两项本就不会进「当下可为」;S0d_p08_master 剧本按候选总数判断该不该问人(=1 必建、≥2 才问、原 PN 硬阻塞)', () => {
|
||||
const s0 = ASSESSMENT_STEPS.find((s) => s.item === 'S0_bind')?.guide ?? '';
|
||||
expect(s0).toContain('当下可为');
|
||||
expect(s0).toContain('不要对计划项用');
|
||||
const s0d = ASSESSMENT_STEPS.find((s) => s.item === 'S0d_p08_master')?.guide ?? '';
|
||||
expect(s0d).toContain('硬阻塞');
|
||||
expect(s0d).toContain('候选只有 1 颗');
|
||||
expect(s0d).toContain('候选总数 = 1');
|
||||
});
|
||||
|
||||
it('S0d_p08_master 剧本按候选总数(不是「不在库的颗数」)判断要不要问人 —— 候选总数 ≥2 时逐颗不在库的都要问(2026-08-27 实测逼出的措辞修正)', () => {
|
||||
const s0d = ASSESSMENT_STEPS.find((s) => s.item === 'S0d_p08_master')?.guide ?? '';
|
||||
expect(s0d).toContain('候选总数');
|
||||
expect(s0d).toContain('不在库');
|
||||
expect(s0d).toMatch(/候选总数\s*≥\s*2/);
|
||||
// 反面提示:「不在库的只有一颗」不该被读成跳过决策卡的理由
|
||||
expect(s0d).toContain('不是跳过决策卡的理由');
|
||||
});
|
||||
|
||||
it('s_bound 哨兵真的检查了「有料号不在库」这件事(都在库时门不该开;退回旧写法会红)', () => {
|
||||
|
||||
Reference in New Issue
Block a user