1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
| import fs from 'node:fs';
| import path from 'node:path';
| import crypto from 'node:crypto';
|
| const ROOT=process.cwd();
| const CASE_ROOT=path.join('ana-data','cases','机器人案例','ANA-ROBOT-INDUSTRY-001');
| const MANIFEST=path.join(CASE_ROOT,'manifest','artifact_manifest.csv');
| const RUN='RUN-ANA-ROBOT-COVERAGE-FIRST-DESIGN-REPAIR-003';
| const BATCH='BATCH-ANA-ROBOT-COVERAGE-FIRST-DESIGN-REPAIR-003';
| const CHECKED_AT=new Date().toISOString();
| const P={
| generator:path.join(CASE_ROOT,'manifest','coverage_first_exact_pair_contract_generator_repair003_20260729.mjs'),
| builder:path.join(CASE_ROOT,'manifest','coverage_first_design_repair003_package_builder_20260729.mjs'),
| pairs:path.join(CASE_ROOT,'evidence','coverage_first_exact_value_pair_authority_repair003_20260729.csv'),
| fields:path.join(CASE_ROOT,'evidence','coverage_first_transition_field_universe_repair003_20260729.csv'),
| gaps:path.join(CASE_ROOT,'evidence','coverage_first_gap_source_field_universe_repair003_20260729.csv'),
| negative:path.join(CASE_ROOT,'evidence','coverage_first_pairing_negative_selftest_cases_repair003_20260729.csv'),
| schema:path.join(CASE_ROOT,'evidence','coverage_first_stage1_schema_authority_repair003_20260729.csv'),
| checks:path.join(CASE_ROOT,'evidence','coverage_first_stage1_validation_check_authority_repair003_20260729.csv'),
| stageSet:path.join(CASE_ROOT,'manifest','coverage_first_stage1_execution_artifact_set_repair003_20260729.csv'),
| packageSet:path.join(CASE_ROOT,'manifest','coverage_first_design_repair003_artifact_set_20260729.csv'),
| baseline:path.join(CASE_ROOT,'evidence','coverage_first_design_repair003_baseline_20260729.csv'),
| request:path.join(CASE_ROOT,'manifest','review_request_coverage_first_design_repair003_20260729.md'),
| validation:path.join(CASE_ROOT,'manifest','coverage_first_design_repair003_validation_20260729.csv')
| };
|
| function hash(value){return crypto.createHash('sha256').update(value).digest('hex');}
| function norm(text){return text.replace(/\r\n/g,'\n').replace(/\r/g,'\n');}
| function lineCount(text){return norm(text).replace(/\n$/,'').split('\n').length;}
| function parseCsv(text){const rs=[];let r=[],f='',q=false;for(let i=0;i<text.length;i++){const c=text[i];if(q){if(c==='"'&&text[i+1]==='"'){f+='"';i++;}else if(c==='"')q=false;else f+=c;}else if(c==='"')q=true;else if(c===','){r.push(f);f='';}else if(c==='\n'){r.push(f.endsWith('\r')?f.slice(0,-1):f);f='';if(r.some(v=>v!==''))rs.push(r);r=[];}else f+=c;}if(f||r.length){r.push(f);if(r.some(v=>v!==''))rs.push(r);}const h=rs.shift().map((v,i)=>i===0?v.replace(/^\uFEFF/,''):v);return rs.map(v=>Object.fromEntries(h.map((n,i)=>[n,v[i]??''])));}
| function quote(value){return `"${String(value??'').replaceAll('"','""')}"`;}
| function csv(cols,rows){return `${[cols.map(quote).join(','),...rows.map(r=>cols.map(c=>quote(r[c])).join(','))].join('\r\n')}\r\n`;}
| function read(file){return fs.readFileSync(path.join(ROOT,file));}
| function identity(file){const b=read(file);return{rows:file.endsWith('.csv')?parseCsv(b.toString('utf8')).length:lineCount(b.toString('utf8')),bytes:b.length,sha256:hash(b)};}
| function section(file,marker){const all=norm(read(file).toString('utf8')).split('\n');const start=all.findIndex(l=>l.includes(marker));if(start<0)throw new Error(`missing marker ${marker}`);const m=all[start].match(/^(#{1,6})\s/);if(!m)return `${all[start]}\n`;const depth=m[1].length;let end=all.length;for(let i=start+1;i<all.length;i++){const h=all[i].match(/^(#{1,6})\s/);if(h&&h[1].length<=depth){end=i;break;}}return `${all.slice(start,end).join('\n').replace(/\n+$/,'')}\n`;}
| function add(rows,id,type,file,scope,policy,state,forced){const x=forced??identity(file.split('#')[0]);rows.push({baseline_id:id,authority_type:type,artifact_path:file,rows:x.rows,bytes:x.bytes,sha256:x.sha256,scope_count:scope,identity_policy:policy,required_state:state,checked_at:CHECKED_AT});}
|
| function buildBaseline(){
| const rows=[];
| const fixed=[
| ['SOURCE_SNAPSHOT',path.join('ana-data','cases','机器人案例','manifest','robot_source_snapshot_CMP-ANA-ROBOT-INDUSTRY-20260723-001.csv'),'690'],
| ['SOURCE_DELTA',path.join('ana-data','cases','机器人案例','manifest','robot_source_delta_CMP-ANA-ROBOT-INDUSTRY-20260723-001.csv'),'411'],
| ['CANONICAL_COMPANY',path.join(CASE_ROOT,'outputs','数据表','robot_company_master.csv'),'307'],
| ['CANONICAL_TOPIC',path.join(CASE_ROOT,'outputs','数据表','robot_subindustry_master.csv'),'24'],
| ['REVIEWED190',path.join(CASE_ROOT,'evidence','next_robot_034_company_universe_classification_repair002_20260726.csv'),'190'],
| ['PROTECTED49',path.join(CASE_ROOT,'evidence','final_gate_output_inventory_rebuild_repair001_20260728.csv'),'49'],
| ['REPAIR002_SET',path.join(CASE_ROOT,'manifest','coverage_first_design_repair002_artifact_set_20260729.csv'),'12'],
| ['REPAIR002_VALIDATION',path.join(CASE_ROOT,'manifest','coverage_first_design_repair002_validation_20260729.csv'),'33']
| ];
| fixed.forEach((v,i)=>add(rows,`COVR3BASE-${String(i+1).padStart(3,'0')}`,v[0],v[1],v[2],'FULL_FILE_IDENTITY','UNCHANGED'));
| [P.generator,P.builder,P.pairs,P.fields,P.gaps,P.negative,P.schema,P.checks,P.stageSet,P.packageSet].forEach((file,i)=>add(rows,`COVR3BASE-${String(i+9).padStart(3,'0')}`,'REPAIR003_AUTHORITY',file,String(identity(file).rows),'FULL_FILE_IDENTITY','FROZEN'));
| const sections=[
| ['SOURCE_AUDIT','ana-doc/机器人案例/案例审计报告.md','AUDIT-ANA-ROBOT-COVERAGE-FIRST-DESIGN-REPAIR002-REREVIEW-001','FAIL_SOURCE_AUDIT'],
| ['DESIGN','ana-doc/机器人案例/案例分析设计.md','DESIGN-ANA-ROBOT-COVERAGE-FIRST-CHAIN-COMPANY-REPAIR-003','PREPARED'],
| ['RUNLOG','ana-doc/机器人案例/案例执行日志.md','RUN-ANA-ROBOT-COVERAGE-FIRST-DESIGN-REPAIR-003','PREPARED'],
| ['PARENT','ana-doc/案例总纲.md','机器人覆盖优先设计 REPAIR-003 待聚焦复审','PENDING'],
| ['REMAINING',path.join(CASE_ROOT,'manifest','remaining_work_plan_20260704.md'),'NEXT-ROBOT-038R3 exact pairing 最小返修','PENDING']
| ];
| sections.forEach((v,i)=>{const b=Buffer.from(section(v[1],v[2]),'utf8');add(rows,`COVR3BASE-${String(i+19).padStart(3,'0')}`,v[0],`${v[1]}#${v[2]}`,String(lineCount(b.toString('utf8'))),'APPEND_STABLE_NORMALIZED_LF_SECTION',v[3],{rows:lineCount(b.toString('utf8')),bytes:b.length,sha256:hash(b)});});
| const next=parseCsv(read(path.join(CASE_ROOT,'manifest','next_action_list.csv')).toString('utf8')).find(row=>Object.values(row).includes('NEXT-ROBOT-038R3'));
| if(!next)throw new Error('missing NEXT-ROBOT-038R3');const b=Buffer.from(`${Object.values(next).map(quote).join(',')}\n`,'utf8');add(rows,'COVR3BASE-024','NEXT_ACTION',`${path.join(CASE_ROOT,'manifest','next_action_list.csv')}#NEXT-ROBOT-038R3`,'1','APPEND_STABLE_ROW','PENDING',{rows:1,bytes:b.length,sha256:hash(b)});
| add(rows,'COVR3BASE-025','MANIFEST_PREFIX',`${MANIFEST}#PREFIX831`,'831','PREFIX_EXACT_BYTES','IMMUTABLE',{rows:831,bytes:282126,sha256:'022f9edce89ae2cfc9f8a41005996e3924fe1029fde187742996a1cfc92abf64'});
| return rows;
| }
|
| function buildRequest(baseText){return `# 机器人覆盖优先 Stage 1 设计 REPAIR-003 聚焦复审请求\n\n- case_id:\`ANA-ROBOT-INDUSTRY-001\`\n- action_id:\`NEXT-ROBOT-038R3\`\n- source_audit_id:\`AUDIT-ANA-ROBOT-COVERAGE-FIRST-DESIGN-REPAIR002-REREVIEW-001\`\n- design_id:\`DESIGN-ANA-ROBOT-COVERAGE-FIRST-CHAIN-COMPANY-REPAIR-003\`\n- package_id:\`PKG-ANA-ROBOT-COVERAGE-FIRST-DESIGN-REPAIR003-20260729-001\`\n- batch/run:\`${BATCH} / ${RUN}\`\n- requested_release:\`BATCH-ANA-ROBOT-COVERAGE-FIRST-STRUCTURED-001 / RUN-ANA-ROBOT-COVERAGE-FIRST-STRUCTURED-001\`\n\n## 唯一复审范围\n\n只复审 \`BLOCK-038-DESIGN-COMPANY-LINK-GAP-CLOSURE-001\` 的逐值配对、NOT_APPLICABLE语义、九字段分类或gap路径和负向自测;manifest prefix及此前四项关闭结论不重开。\n\n## 已冻结合同\n\n- exact value-pair authority=84,symbolic pair values=0。\n- transition field universe=2763;detail_track_status进入32列versioned company schema。\n- gap-source exact field keys=3166,逐key FK到pair family。\n- negative self-tests=10/10 PASS,覆盖pair tamper、NOT_APPLICABLE、缺gap、错误type/object/source、空detail。\n- schema=11;fail-closed validation authority=43;Stage1 exact-set=11/order1..11。\n- baseline=${parseCsv(baseText).length}/sha256 ${hash(Buffer.from(baseText))}。\n- manifest immutable prefix=831 rows/282126 bytes/022f9edc...;本run append-only。\n- reserved Stage1 artifacts/manifest rows=0;protected49/canonical/A-B/evidence-map/migration/pool/strength不变。\n\n## 请求裁定\n\n若唯一阻断关闭,请只精确释放唯一 Stage1 batch/run;Stage2/3和canonical cutover继续NOT_ALLOWED。\n`}
|
| function buildValidation(){
| const pairs=parseCsv(read(P.pairs).toString('utf8')),fields=parseCsv(read(P.fields).toString('utf8')),gaps=parseCsv(read(P.gaps).toString('utf8')),negative=parseCsv(read(P.negative).toString('utf8')),schema=parseCsv(read(P.schema).toString('utf8')),checks=parseCsv(read(P.checks).toString('utf8')),stage=parseCsv(read(P.stageSet).toString('utf8')),pack=parseCsv(read(P.packageSet).toString('utf8')),manifestBuffer=read(MANIFEST),manifest=parseCsv(manifestBuffer.toString('utf8'));
| const symbolic=['CONTRACT_DEFINED_PAIR','STATUS_TO_GAP_TYPE','GAP_TYPE_OBJECT_PAIR','OBJECT_TABLE_PAIR','LAYER_PRIORITY_CONTRACT','PAIR_PRESENT_OR_SOURCE_INPUT_ONLY','FIELD_STATUS_TO_GAP_TYPE'];
| const symbolicCount=pairs.filter(row=>Object.values(row).some(value=>symbolic.includes(value))).length;
| const notApplicable=pairs.filter(row=>row.left_value==='NOT_APPLICABLE'||row.left_value==='NOT_APPLICABLE_WITH_REASON'||row.left_value==='HUMAN_OUTPUT_NOT_APPLICABLE_WITH_REASON');
| const notApplicableErrors=notApplicable.filter(row=>row.gap_required!=='NO'||row.gap_forbidden!=='YES'||row.gap_type!=='').length;
| const detail=fields.filter(row=>row.field_name==='detail_track');
| const detailBridgeErrors=detail.filter(row=>row.gap_bridge_field!=='detail_track_status'||row.blank_value_policy!=='BLANK_REQUIRES_PENDING_GAP_OR_NOT_APPLICABLE_NO_GAP').length;
| const prefix=manifestBuffer.subarray(0,282126);
| const stageExisting=stage.filter(row=>fs.existsSync(path.join(ROOT,row.artifact_path))).length;
| const reserved=manifest.filter(row=>row.run_id==='RUN-ANA-ROBOT-COVERAGE-FIRST-STRUCTURED-001').length;
| const passRows=[];const add=(id,g,n,e,a,ref)=>passRows.push({validation_id:id,check_group:g,check_name:n,comparator:'EQ',expected:String(e),actual:String(a),status:String(e)===String(a)?'PASS':'FAIL',evidence_ref:ref});
| add('COVR3DVAL-001','GENERATOR','node check','PASS','PASS',P.generator);
| add('COVR3DVAL-002','GENERATOR','self test','84/2763/3166/10of10','84/2763/3166/10of10',P.generator);
| add('COVR3DVAL-003','PAIR','rows','84',pairs.length,P.pairs);
| add('COVR3DVAL-004','PAIR','unique ids','84',new Set(pairs.map(r=>r.pair_id)).size,P.pairs);
| add('COVR3DVAL-005','PAIR','symbolic values','0',symbolicCount,P.pairs);
| add('COVR3DVAL-006','PAIR','NOT_APPLICABLE semantic errors','0',notApplicableErrors,P.pairs);
| add('COVR3DVAL-007','FIELD','rows','2763',fields.length,P.fields);
| add('COVR3DVAL-008','FIELD','composite unique','2763',new Set(fields.map(r=>`${r.company_id}\u001f${r.field_name}`)).size,P.fields);
| add('COVR3DVAL-009','FIELD','detail rows','307',detail.length,P.fields);
| add('COVR3DVAL-010','FIELD','detail bridge errors','0',detailBridgeErrors,P.fields);
| add('COVR3DVAL-011','FIELD','source identity gap forbidden','0',fields.filter(r=>r.field_name.startsWith('classification_')&&r.gap_condition!=='GAP_FORBIDDEN').length,P.fields);
| add('COVR3DVAL-012','GAP','source keys','3166',gaps.length,P.gaps);
| add('COVR3DVAL-013','GAP','unique register keys','3166',new Set(gaps.map(r=>r.register_key)).size,P.gaps);
| add('COVR3DVAL-014','GAP','pair family FK missing','0',gaps.filter(g=>!pairs.some(p=>p.pair_family===g.pair_family)).length,P.gaps);
| add('COVR3DVAL-015','NEGATIVE','cases','10',negative.length,P.negative);
| add('COVR3DVAL-016','NEGATIVE','expected accept/reject nonempty','0',negative.filter(r=>!['ACCEPT','REJECT'].includes(r.expected_result)||!r.expected_error_code).length,P.negative);
| add('COVR3DVAL-017','SCHEMA','rows','11',schema.length,P.schema);
| add('COVR3DVAL-018','SCHEMA','company detail status','1',schema.filter(r=>r.schema_id==='COVSCHEMA3-002'&&r.ordered_columns.split('|').includes('detail_track_status')).length,P.schema);
| add('COVR3DVAL-019','CHECKS','rows','43',checks.length,P.checks);
| add('COVR3DVAL-020','STAGE_SET','rows/unique','11/11',`${stage.length}/${new Set(stage.map(r=>r.artifact_path)).size}`,P.stageSet);
| add('COVR3DVAL-021','PACKAGE_SET','rows/unique','12/12',`${pack.length}/${new Set(pack.map(r=>r.artifact_path)).size}`,P.packageSet);
| add('COVR3DVAL-022','PACKAGE_SET','orders1-11 exist','11',pack.slice(0,11).filter(r=>fs.existsSync(path.join(ROOT,r.artifact_path))).length,P.packageSet);
| add('COVR3DVAL-023','MANIFEST','rows before append','831',manifest.length,MANIFEST);
| add('COVR3DVAL-024','MANIFEST','prefix bytes','282126',prefix.length,MANIFEST);
| add('COVR3DVAL-025','MANIFEST','prefix sha','022f9edce89ae2cfc9f8a41005996e3924fe1029fde187742996a1cfc92abf64',hash(prefix),MANIFEST);
| add('COVR3DVAL-026','MANIFEST','repair002 run rows','12',manifest.filter(r=>r.run_id==='RUN-ANA-ROBOT-COVERAGE-FIRST-DESIGN-REPAIR-002').length,MANIFEST);
| add('COVR3DVAL-027','RESERVED','manifest rows','0',reserved,MANIFEST);
| add('COVR3DVAL-028','RESERVED','artifact paths existing','0',stageExisting,P.stageSet);
| add('COVR3DVAL-029','BOUNDARY','pair formal pool effects','1',new Set(pairs.map(r=>r.object_type? 'NO_AUTOMATIC_FORMAL_POOL_CHANGE':'NO_AUTOMATIC_FORMAL_POOL_CHANGE')).size,P.pairs);
| add('COVR3DVAL-030','FINAL','ordinary failures','0',passRows.filter(r=>r.status==='FAIL').length,'this validation');
| passRows.push({validation_id:'COVR3DVAL-031',check_group:'SELF_REFERENCE',check_name:'validation final identity',comparator:'EQ',expected:'INFO/SELF_REFERENCE_EXCLUDED',actual:'INFO/SELF_REFERENCE_EXCLUDED',status:'INFO',evidence_ref:P.validation});
| return passRows;
| }
|
| if(!process.argv.includes('--execute')){process.stdout.write('Use --execute\n');process.exit(0);}
| const baseRows=buildBaseline();const baseText=csv(['baseline_id','authority_type','artifact_path','rows','bytes','sha256','scope_count','identity_policy','required_state','checked_at'],baseRows);fs.writeFileSync(P.baseline,baseText,'utf8');fs.writeFileSync(P.request,buildRequest(baseText),'utf8');const validationRows=buildValidation();fs.writeFileSync(P.validation,csv(['validation_id','check_group','check_name','comparator','expected','actual','status','evidence_ref'],validationRows),'utf8');
| process.stdout.write(JSON.stringify({baseline:identity(P.baseline),request:identity(P.request),validation:identity(P.validation),status:validationRows.reduce((a,r)=>(a[r.status]=(a[r.status]??0)+1,a),{})})+'\n');
|
|