/**
* PedagogyRules v4.0.0 — L1/L2 教研规则诊断引擎
*
* ========== v4 更新 ==========
* 新增 5 个校验维度(来自 16 个教研 Skill):
* 6. 题型合规检测(componentCompliance)— dialogue/info config skills
* 7. 配置字段完整性(configIntegrity)— audit_l1_config 7项自动检查
* 8. 知识点掌握度预测(masteryPrediction)— knowledge-mastery-calculator
* 9. 格式规范质量(formatQuality)— 文本输出规范校验
* 10. 语法问题检测(grammarIssues)— 三单/拼写/混用检测
*
* 数据源:
* - business_knowledge/L1_word_list.json + L2_word_list.json
* - business_knowledge/L1_pattern_list.json + L2_pattern_list.json
* - MEMORY.md 教研规范
* - 16 个 skill 规则文件
*
* 接入:
* API: PedagogyRules.evaluate(summary, item, level, options)
*/
(function(g){"use strict";
var VERSION = '4.0.0';
// ═══════════ DATA: WORD LISTS ═══════════
var W={L1:{"red":{"pos":"adj","meaning":"红色的","unit":"S0-U0-L1","diff":1},"hat":{"pos":"n","meaning":"帽子","unit":"S0-U0-L1","diff":1},"blue":{"pos":"adj","meaning":"蓝的","unit":"S0-U0-L1","diff":1},"bag":{"pos":"n","meaning":"袋,包","unit":"S0-U0-L1","diff":1},"orange":{"pos":"n","meaning":"橙子","unit":"S1-U10-L3","diff":1},"green":{"pos":"adj","meaning":"绿色的","unit":"S0-U0-L2","diff":1},"dress":{"pos":"n","meaning":"连衣裙","unit":"S0-U0-L2","diff":1},"there":{"pos":"adv","meaning":"那里","unit":"S0-U0-L3","diff":1},"put":{"pos":"v","meaning":"放","unit":"S0-U0-L3","diff":1},"purple":{"pos":"adj","meaning":"紫色的","unit":"S0-U0-L5","diff":1},"give":{"pos":"v","meaning":"给","unit":"S0-U0-L3","diff":1},"water":{"pos":"n","meaning":"水","unit":"S0-U0-L4","diff":1},"here":{"pos":"adv","meaning":"在这里","unit":"S0-U0-L4","diff":1},"dirty":{"pos":"adj","meaning":"肮脏的","unit":"S0-U0-L4","diff":1},"clean":{"pos":"v","meaning":"清洁","unit":"S0-U0-L4","diff":1},"pink":{"pos":"adj","meaning":"粉红色的","unit":"S0-U0-L2","diff":1},"get":{"pos":"v","meaning":"收到","unit":"","diff":1},"wall":{"pos":"n","meaning":"墙","unit":"S1-U1-L1","diff":1},"table":{"pos":"n","meaning":"桌子","unit":"S1-U1-L1","diff":1},"floor":{"pos":"n","meaning":"地板","unit":"S1-U1-L1","diff":1},"hand":{"pos":"n","meaning":"手","unit":"S1-U1-L2","diff":1},"foot":{"pos":"n","meaning":"脚","unit":"S1-U1-L2","diff":1},"black":{"pos":"adj","meaning":"黑的","unit":"S1-U1-L2","diff":1},"tomato":{"pos":"n","meaning":"西红柿","unit":"S1-U1-L3","diff":1},"fish":{"pos":"n","meaning":"鱼","unit":"S1-U1-L3","diff":1},"chicken":{"pos":"n","meaning":"鸡肉","unit":"S1-U1-L3","diff":1},"nose":{"pos":"n","meaning":"鼻子","unit":"S1-U1-L4","diff":1},"eye":{"pos":"n","meaning":"眼睛","unit":"S1-U1-L4","diff":1},"brown":{"pos":"adj","meaning":"棕色的","unit":"S1-U1-L4","diff":1},"yellow":{"pos":"adj","meaning":"黄色的","unit":"S1-U1-L5","diff":1},"white":{"pos":"adj","meaning":"白色的","unit":"S1-U1-L5","diff":1},"go":{"pos":"v","meaning":"去,走","unit":"S1-U2-L1","diff":1},"dog":{"pos":"n","meaning":"狗","unit":"S1-U2-L1","diff":1},"come":{"pos":"v","meaning":"来","unit":"S1-U2-L1","diff":1},"cat":{"pos":"n","meaning":"猫","unit":"S1-U2-L1","diff":1},"pie":{"pos":"n","meaning":"馅饼","unit":"S1-U2-L2","diff":1},"can":{"pos":"v","meaning":"能,会","unit":"S1-U2-L4","diff":1},"open":{"pos":"adj","meaning":"开着的","unit":"","diff":1},"happy":{"pos":"adj","meaning":"快乐的","unit":"S1-U2-L5","diff":1},"see":{"pos":"v","meaning":"看见","unit":"S1-U3-L1","diff":1},"1":{"pos":"num","meaning":"1","unit":"S1-U3-L1","diff":1},"paper":{"pos":"adj","meaning":"纸质的","unit":"","diff":1},"book":{"pos":"n","meaning":"书","unit":"S1-U3-L2","diff":1},"3":{"pos":"num","meaning":"3","unit":"S1-U3-L2","diff":1},"2":{"pos":"num","meaning":"2","unit":"S1-U3-L2","diff":1},"pen":{"pos":"n","meaning":"钢笔","unit":"S1-U3-L3","diff":1},"box":{"pos":"n","meaning":"盒子","unit":"S1-U3-L3","diff":1},"4":{"pos":"num","meaning":"4","unit":"S1-U3-L3","diff":1},"6":{"pos":"num","meaning":"6","unit":"S1-U3-L4","diff":1},"5":{"pos":"num","meaning":"5","unit":"S1-U3-L4","diff":1},"sing":{"pos":"v","meaning":"唱","unit":"S1-U4-L1","diff":1},"eat":{"pos":"v","meaning":"吃","unit":"S1-U4-L2","diff":1},"7":{"pos":"num","meaning":"7","unit":"S1-U4-L2","diff":1},"rug":{"pos":"n","meaning":"小地毯","unit":"S1-U4-L3","diff":1},"door":{"pos":"n","meaning":" 门","unit":"","diff":1},"bed":{"pos":"n","meaning":"床","unit":"S1-U4-L3","diff":1},"9":{"pos":"num","meaning":"9","unit":"S1-U4-L4","diff":1},"8":{"pos":"num","meaning":"8","unit":"S1-U4-L4","diff":1},"10":{"pos":"num","meaning":"10","unit":"S1-U4-L5","diff":1},"zoo":{"pos":"n","meaning":"动物园","unit":"","diff":1},"zebra":{"pos":"n","meaning":"斑马","unit":"S1-U7-L2","diff":1},"young":{"pos":"adj","meaning":"年轻的","unit":"","diff":1},"year":{"pos":"n","meaning":"年","unit":"","diff":1},"write":{"pos":"v","meaning":"写","unit":"","diff":1},"woman":{"pos":"n","meaning":"女人","unit":"S1-U5-L1","diff":1},"window":{"pos":"n","meaning":"窗户","unit":"S1-U12-L4","diff":1},"warm":{"pos":"adj","meaning":"温暖的","unit":"","diff":1},"want":{"pos":"v","meaning":"想要","unit":"","diff":1},"walk":{"pos":"v","meaning":"走","unit":"S1-U7-L2","diff":1},"very":{"pos":"adv","meaning":"非常","unit":"","diff":1},"under":{"pos":"prep","meaning":"在...下面","unit":"S2-U14-L5","diff":1},"try":{"pos":"v","meaning":"尝试","unit":"S1-U12-L5","diff":1},"tree":{"pos":"n","meaning":"树","unit":"S1-U7-L1","diff":1},"train":{"pos":"n","meaning":"火车","unit":"S1-U8-L1","diff":1},"too":{"pos":"adv","meaning":"也","unit":"S1-U12-L2","diff":1},"tomorrow":{"pos":"n","meaning":"明天","unit":"","diff":1},"today":{"pos":"n","meaning":"今天","unit":"","diff":1},"tiger":{"pos":"n","meaning":"老虎","unit":"S1-U5-L3","diff":1},"those":{"pos":"pron","meaning":"那些","unit":"S1-U12-L1","diff":1},"this":{"pos":"pron","meaning":"这个","unit":"S1-U12-L1","diff":1},"these":{"pos":"pron","meaning":"这些","unit":"S1-U12-L1","diff":1},"that":{"pos":"pron","meaning":"那个","unit":"S1-U12-L1","diff":1},"tell":{"pos":"v","meaning":"告诉","unit":"","diff":1},"teacher":{"pos":"n","meaning":"老师","unit":"S2-U14-L2","diff":1},"talk":{"pos":"v","meaning":"说话","unit":"","diff":1},"swim":{"pos":"v","meaning":"游泳","unit":"S1-U11-L5","diff":1},"sun":{"pos":"n","meaning":"太阳","unit":"S1-U8-L2","diff":1},"study":{"pos":"v","meaning":"学习","unit":"S2-U14-L1","diff":1},"student":{"pos":"n","meaning":"学生","unit":"S2-U14-L1","diff":1},"speak":{"pos":"v","meaning":"说","unit":"","diff":1},"some":{"pos":"det","meaning":"一些","unit":"","diff":1},"sofa":{"pos":"n","meaning":"沙发","unit":"","diff":1},"sock":{"pos":"n","meaning":"袜子","unit":"","diff":1},"small":{"pos":"adj","meaning":"小的","unit":"S1-U9-L1","diff":1},"sleep":{"pos":"v","meaning":"睡觉","unit":"S1-U7-L4","diff":1},"skirt":{"pos":"n","meaning":"裙子","unit":"S1-U9-L4","diff":1},"sit":{"pos":"v","meaning":"坐下","unit":"S1-U8-L1","diff":1},"sister":{"pos":"n","meaning":"姐姐、妹妹","unit":"S1-U8-L1","diff":1},"short":{"pos":"adj","meaning":"短的","unit":"","diff":1},"shoe":{"pos":"n","meaning":"鞋","unit":"","diff":1},"shirt":{"pos":"n","meaning":"衬衫","unit":"S1-U9-L1","diff":1},"ship":{"pos":"n","meaning":"船","unit":"","diff":1},"sheep":{"pos":"n","meaning":"绵羊","unit":"S1-U5-L3","diff":1},"school":{"pos":"n","meaning":"学校","unit":"S2-U14-L1","diff":1},"say":{"pos":"v","meaning":"说","unit":"","diff":1},"sad":{"pos":"adj","meaning":"悲伤的","unit":"","diff":1},"run":{"pos":"v","meaning":"跑","unit":"","diff":1},"ruler":{"pos":"n","meaning":"尺子","unit":"","diff":1},"room":{"pos":"n","meaning":"房间","unit":"","diff":1},"rice":{"pos":"n","meaning":"米饭","unit":"S1-U6-L4","diff":1},"read":{"pos":"v","meaning":"阅读","unit":"","diff":1},"radio":{"pos":"n","meaning":"收音机","unit":"S1-U9-L2","diff":1},"potato":{"pos":"n","meaning":"土豆","unit":"S1-U7-L3","diff":1},"play":{"pos":"v","meaning":"玩","unit":"S2-U14-L1","diff":1},"plane":{"pos":"n","meaning":"飞机","unit":"S1-U8-L3","diff":1},"pig":{"pos":"n","meaning":"猪","unit":"S1-U7-L4","diff":1},"phone":{"pos":"v","meaning":"给…...打电话","unit":"","diff":1},"people":{"pos":"n","meaning":"人","unit":"","diff":1},"pencil":{"pos":"n","meaning":"铅笔","unit":"","diff":1},"pea":{"pos":"n","meaning":"豌豆","unit":"","diff":1},"pe":{"pos":"n","meaning":"体育","unit":"S1-U10-L4","diff":1},"paint":{"pos":"v","meaning":"(用颜料)绘画","unit":"","diff":1},"one":{"pos":"pron","meaning":"一个人(或物)","unit":"","diff":1},"old":{"pos":"adj","meaning":"年老的","unit":"","diff":1},"now":{"pos":"adv","meaning":"现在","unit":"","diff":1},"night":{"pos":"n","meaning":"夜晚","unit":"S1-U12-L5","diff":1},"nice":{"pos":"adj","meaning":"好的","unit":"S1-U6-L3","diff":1},"new":{"pos":"adj","meaning":"新的","unit":"S1-U9-L2","diff":1},"mum":{"pos":"n","meaning":"妈妈","unit":"S1-U8-L4","diff":1},"mouth":{"pos":"n","meaning":"嘴巴","unit":"","diff":1},"mother":{"pos":"n","meaning":"母亲","unit":"","diff":1},"morning":{"pos":"n","meaning":"早上","unit":"S1-U12-L5","diff":1},"month":{"pos":"n","meaning":"月","unit":"","diff":1},"monkey":{"pos":"n","meaning":"猴子","unit":"S1-U7-L1","diff":1},"minute":{"pos":"n","meaning":"分钟","unit":"","diff":1},"mine":{"pos":"pron","meaning":"我的","unit":"","diff":1},"milk":{"pos":"n","meaning":"牛奶","unit":"S1-U5-L2","diff":1},"men":{"pos":"n","meaning":"男人(man 的复数)","unit":"","diff":1},"meat":{"pos":"n","meaning":"肉类","unit":"S1-U10-L3","diff":1},"me":{"pos":"pron","meaning":"我","unit":"S1-U12-L2","diff":1},"mat":{"pos":"n","meaning":"地垫","unit":"S2-U14-L4","diff":1},"many":{"pos":"det","meaning":"许多","unit":"","diff":1},"man":{"pos":"n","meaning":"男人","unit":"S1-U5-L1","diff":1},"make":{"pos":"v","meaning":"制造","unit":"S1-U6-L3","diff":1},"love":{"pos":"v","meaning":"爱","unit":"S1-U12-L2","diff":1},"lots of":{"pos":"det","meaning":"大量的","unit":"","diff":1},"long":{"pos":"adj","meaning":"长的","unit":"S1-U7-L5 ","diff":1}},L2:{"dentist":{"pos":"n","meaning":"牙医","cefr":"A1","cambridge":"Movers","diff":2},"department":{"pos":"n","meaning":"部门","cefr":"A2","cambridge":"KET","diff":2},"department store":{"pos":"n","meaning":"百货商店","cefr":"A2","cambridge":"KET","diff":2},"describe":{"pos":"v","meaning":"描述","cefr":"A2","cambridge":"KET","diff":2},"desert":{"pos":"v","meaning":"遗弃","cefr":"A2","cambridge":"KET","diff":2},"design":{"pos":"v","meaning":"设计","cefr":"A2","cambridge":"KET","diff":2},"dessert":{"pos":"n","meaning":"甜点","cefr":"A2","cambridge":"KET","diff":2},"detailed":{"pos":"adj","meaning":"详细的","cefr":"A2","cambridge":"KET","diff":2},"diary":{"pos":"n","meaning":"日记","cefr":"A2","cambridge":"KET/Flyers","diff":2},"dictionary":{"pos":"n","meaning":"词典","cefr":"A2","cambridge":"KET/Flyers","diff":2},"die":{"pos":"v","meaning":"消失;灭亡","cefr":"A2","cambridge":"KET","diff":2},"difference":{"pos":"n","meaning":"差别","cefr":"A1","cambridge":"Movers","diff":2},"different":{"pos":"adj","meaning":"不同的","cefr":"A1","cambridge":"Movers","diff":2},"difficult":{"pos":"adj","meaning":"困难的","cefr":"A1","cambridge":"Movers","diff":2},"digital":{"pos":"adj","meaning":"数字的","cefr":"A2","cambridge":"KET","diff":2},"digital camera":{"pos":"n","meaning":"数码相机","cefr":"A2","cambridge":"KET","diff":2},"dinosaur":{"pos":"n","meaning":"恐龙","cefr":"A2","cambridge":"KET/Flyers","diff":2},"diploma":{"pos":"n","meaning":"文凭","cefr":"A2","cambridge":"KET","diff":2},"directions":{"pos":"n","meaning":"方向","cefr":"A2","cambridge":"KET","diff":2},"dirty":{"pos":"adj","meaning":"脏的","cefr":"Pre-A1","cambridge":"Starters","diff":2},"disco":{"pos":"n","meaning":"迪斯科","cefr":"A2","cambridge":"KET","diff":2},"discount":{"pos":"n","meaning":"折扣","cefr":"A2","cambridge":"KET","diff":2},"discover":{"pos":"v","meaning":"发现","cefr":"A2","cambridge":"KET","diff":2},"discuss":{"pos":"vt","meaning":"讨论","cefr":"A2","cambridge":"KET","diff":2},"dish":{"pos":"n","meaning":"菜肴","cefr":"A2","cambridge":"KET","diff":2},"display":{"pos":"v","meaning":"显示","cefr":"B1","cambridge":"PET","diff":2},"dive":{"pos":"v","meaning":"潜水","cefr":"A2","cambridge":"KET","diff":2},"diving":{"pos":"n","meaning":"潜水","cefr":"A2","cambridge":"KET","diff":2},"doctor":{"pos":"n","meaning":"医生","cefr":"A1","cambridge":"Movers","diff":2},"document":{"pos":"n","meaning":"文件","cefr":"A2","cambridge":"KET","diff":2},"dollar":{"pos":"n","meaning":"美元","cefr":"A2","cambridge":"KET","diff":2},"dot":{"pos":"n","meaning":"点","cefr":"A2","cambridge":"KET","diff":2},"double":{"pos":"v","meaning":"使加倍","cefr":"A2","cambridge":"KET","diff":2},"double room":{"pos":"phrase","meaning":"双人间","cefr":"A2","cambridge":"KET","diff":2},"doubt":{"pos":"v","meaning":"怀疑","cefr":"B1","cambridge":"PET","diff":2},"download":{"pos":"v","meaning":"下载","cefr":"A2","cambridge":"KET","diff":2},"downstairs":{"pos":"adj","meaning":"楼下的","cefr":"A2","cambridge":"KET","diff":2},"dozen":{"pos":"det","meaning":"十二","cefr":"B1","cambridge":"PET","diff":2},"draw":{"pos":"n","meaning":"抽签","cefr":"A2","cambridge":"KET","diff":2},"drawer":{"pos":"n","meaning":"抽屉","cefr":"A2","cambridge":"KET","diff":2},"dream":{"pos":"v","meaning":"梦想","cefr":"A2","cambridge":"KET","diff":2},"dress":{"pos":"v","meaning":"穿衣服","cefr":"A2","cambridge":"KET","diff":2},"dressed":{"pos":"adj","meaning":"穿着衣服的","cefr":"A2","cambridge":"KET","diff":2},"drive":{"pos":"v","meaning":"驾车送(人)","cefr":"A2","cambridge":"KET","diff":2},"driving licence":{"pos":"n","meaning":"驾驶执照","cefr":"A2","cambridge":"KET","diff":2},"drop":{"pos":"n","meaning":"滴","cefr":"A2","cambridge":"KET","diff":2},"drugstore":{"pos":"n","meaning":"药店","cefr":"A2","cambridge":"KET","diff":2},"drum":{"pos":"n","meaning":"鼓","cefr":"A2","cambridge":"KET/Flyers","diff":2},"dry":{"pos":"v","meaning":"变干","cefr":"A1","cambridge":"Movers","diff":2},"during":{"pos":"prep","meaning":"在……期间","cefr":"A2","cambridge":"KET/Flyers","diff":2},"duty-free":{"pos":"adj","meaning":"免税的","cefr":"B1","cambridge":"PET","diff":2},"dvd player":{"pos":"n","meaning":"DVD播放机","cefr":"A2","cambridge":"KET","diff":2}}},P={L1:[{"structure":"be + adj","module":"形容词结构","mid":"M1","examples":["I am happy today.","I am sad today."],"meaning":["今天我很开心。","今天我很难过。"]},{"structure":"feel + adj","module":"系表结构","mid":"M1","examples":["I feel tired.","I feel happy."],"meaning":["我感到累。","我感到开心。"]},{"structure":"look + adj","module":"系表结构","mid":"M1","examples":["You look happy.","He looks tired."],"meaning":["你看起来很高兴。","他看起来累了。"]},{"structure":"adj and adj","module":"并列形容词","mid":"M1","examples":["The room is big and clean.","The dog is small and cute."],"meaning":["房间又大又干净。","这只狗又小又可爱。"]},{"structure":"S + V","module":"动词与时态","mid":"M2","examples":["I read books.","We go to school."],"meaning":["我读书。","我们去上学。"]},{"structure":"S + be + V-ing","module":"动词与时态","mid":"M2","examples":["I am reading now.","She is cooking."],"meaning":["我正在读书。","她在做饭。"]},{"structure":"do/does + V","module":"动词与时态","mid":"M2","examples":["Do you like apples?","Does he like milk?"],"meaning":["你喜欢苹果吗?","他喜欢牛奶吗?"]},{"structure":"can + V","module":"情态动词","mid":"M2","examples":["I can swim.","Can you help me?"],"meaning":["我会游泳。","你能帮我吗?"]}],L2:[{"structure":"S + be + adj + to + V","module":"复合结构","mid":"M1","examples":["I am happy to see you."],"meaning":["我很开心见到你。"]}]};
// ═══════════ BENCHMARKS ═══════════
var BM={L1:{idealRounds:6,targetWordsPerRound:3,idealWordCount:7,targetExposure:{min:2,ideal:3},dialogRounds:{min:4,max:12,ideal:8},sentenceLength:{min:3,max:8,ideal:5}},L2:{idealRounds:8,targetWordsPerRound:4,idealWordCount:9,targetExposure:{min:2,ideal:4},dialogRounds:{min:6,max:16,ideal:10},sentenceLength:{min:4,max:12,ideal:7}}};
var DIFF_WEIGHT={A0:0,A1:1,A2:2,B1:4,B2:6,C1:8,C2:10,Pre_A1:0.5,Starters:0,Movers:1,Flyers:2,KET:3,PET:5};
// ═══════════ BRITISH SPELLING MAP (from MEMORY.md + skills) ═══════════
var BRITISH_SPELLING={color:"colour",favorite:"favourite",center:"centre",theater:"theatre",meter:"metre",liter:"litre",traveling:"travelling",traveled:"travelled",canceled:"cancelled",canceling:"cancelling",dialog:"dialogue",catalog:"catalogue",analog:"analogue",monolog:"monologue",program:"programme",ton:"tonne",gray:"grey",practice:"practise",license:"licence",defense:"defence",offense:"offence","pretense":"pretence",realize:"realise",recognize:"recognise",organize:"organise",apologize:"apologise",analyze:"analyse",paralyze:"paralyse","plow":"plough","draft":"draught","jewelry":"jewellery","maneuver":"manoeuvre","skeptical":"sceptical","behavior":"behaviour","neighbor":"neighbour","harbor":"harbour","labor":"labour","favor":"favour","honor":"honour","colorful":"colourful","flavor":"flavour","humor":"humour","rumor":"rumour","savor":"savour","vapor":"vapour","rigor":"rigour","vigor":"vigour","armor":"armour","clamor":"clamour","demeanor":"demeanour","splendor":"splendour","rancor":"rancour","odor":"odour","parlor":"parlour","endeavor":"endeavour","ardor":"ardour","candor":"candour","succor":"succour","valour":"valor","enrolment":"enrollment","fulfil":"fulfill","distil":"distill","instil":"instill","skilful":"skillful","wilful":"willful","enrol":"enroll","instalment":"installment","fibre":"fiber","litre":"liter","lustre":"luster","meagre":"meager","sceptre":"scepter","sombre":"somber","theatre":"theater","calibre":"caliber","centre":"center","goitre":"goiter","manoeuvre":"maneuver","metre":"meter","mitre":"miter","ochre":"ocher","reconnoitre":"reconnoiter","sabre":"saber","saltpetre":"saltpeter","sepulchre":"sepulcher","sombre":"somber","spectre":"specter","cheque":"check","chequer":"checker","kosher":"kosher"};
// ═══════════ COMPONENT TYPE RULES (from dialogue-*/info-* config skills) ═══════════
var COMPONENT_RULES={"dialogue_reading":{label:"对话朗读",family:"dialogue",hasCorrectAnswer:false,fields:{readingSentence:{required:true,max:1,desc:"朗读句子,末尾必须加(朗读)"},contextIntro:{required:false,desc:"情境引入"}},imageRequired:{base:false,withImage:true},optionsRequired:false,maxSentenceLength:15,check:function(c){var issues=[];var s=c.readingSentence||c.sentence||c.interactiveContent||"";if(!s)issues.push({field:"readingSentence",msg:"缺少朗读句子"});if(s&&!/[((]朗读[))]$/.test(s))issues.push({field:"readingSentence",msg:["朗读句子末尾缺少(朗读)标记:",s].join(" ")});return issues;}},"dialogue_choose":{label:"对话选择",family:"dialogue",hasCorrectAnswer:true,fields:{options:{required:true,min:2,desc:"2+选项,一个标(正确)"},contextIntro:{required:false}},imageRequired:{base:false,withImage:true},optionsRequired:true,maxCorrectCount:1,check:function(c){var issues=[],opts=c.options||c.choices||[];if(opts.length<2)issues.push({field:"options","msg":"选项不足2个(当前"+opts.length+"个)"});var corrects=opts.filter(function(o){return o&&(o.isCorrect||o.correct||/[((]正确[))]/.test(o.text||o.label||""));});if(corrects.length===0)issues.push({field:"options","msg":"缺少正确选项(需标(正确))"});if(corrects.length>1)issues.push({field:"options","msg":"多个选项标为正确(需唯一正确)"});opts.forEach(function(o,i){var fb=o.feedback||o.fb;if(!fb)issues.push({field:"options","msg":["选项"+(i+1)+"缺少反馈台词"].join(" ")});});return issues;}},"dialogue_selective_reading":{label:"对话选读",family:"dialogue",hasCorrectAnswer:false,fields:{options:{required:true,min:2,max:4,desc:"2-4选项,无正确,每个有反馈"},requirement:{fixed:"选择一个你想表达的观点"}},imageRequired:{base:false,withImage:true},optionsRequired:true,noCorrectAnswer:true,feedbackPerOption:true,check:function(c){var issues=[],opts=c.options||c.choices||[],req=c.requirement||c.interactiveContent||"";if(req&&!req.includes("选择一个你想表达的观点"))issues.push({field:"requirement","msg":['互动要求固定为"选择一个你想表达的观点",当前: '+req].join(" ")});if(opts.length<2)issues.push({field:"options","msg":"选项不足2个"});opts.forEach(function(o,i){if(o&&(o.isCorrect||o.correct))issues.push({field:"options","msg":["选项"+(i+1)+"不应标注正确(选读无正确选项)"].join(" ")});var fb=o&&(o.feedback||o.fb);if(!fb)issues.push({field:"options","msg":["选项"+(i+1)+"缺少反馈(选读每个选项必有反馈)"].join(" ")});});return issues;}},"dialogue_fill_in_the_blanks":{label:"对话挖空",family:"dialogue",hasCorrectAnswer:true,fields:{stem:{required:true,desc:"含___的句子"},options:{required:true,min:2,desc:"选项列表,正确标(正确)"},feedback:{required:true,desc:"正确+错误反馈"}},imageRequired:{base:false,withImage:true},optionsRequired:true,blankCount:1,check:function(c){var issues=[],stem=c.stem||c.sentence||c.interactiveContent||"";if(!stem)issues.push({field:"stem","msg":"缺少题干句子"});if(stem&&!/___|____/.test(stem))issues.push({field:"stem","msg":"题干缺少挖空标记 ___"});var opts=c.options||c.choices||[];if(opts.length<2)issues.push({field:"options","msg":"选项不足2个"});var corrects=opts.filter(function(o){return o&&(o.isCorrect||o.correct||/[((]正确[))]/.test(o.text||o.label||""));});if(corrects.length!==1)issues.push({field:"options","msg":["应有1个正确选项,当前"+corrects.length+"个"].join(" ")});return issues;}},"dialogue_sentence_building":{label:"对话组句",family:"dialogue",hasCorrectAnswer:true,fields:{options:{required:true,min:4,max:8,desc:"单词/短语选项"},answer:{required:true,desc:"完整句子"},hint:{required:false,desc:"辅助信息"}},imageRequired:{base:false,withImage:true},optionsRequired:true,maxDistractors:1,check:function(c){var issues=[],opts=c.options||c.choices||[],ans=c.answer||c.correctSentence||"";if(opts.length<4)issues.push({field:"options","msg":"组句选项至少4个(当前"+opts.length+"个)"});if(opts.length>8)issues.push({field:"options","msg":"组句选项最多8个(当前"+opts.length+"个)"});if(!ans)issues.push({field:"answer","msg":"缺少正确句子答案"});return issues;}},"info_word_spelling":{label:"信息拼词",family:"info",hasCorrectAnswer:true,fields:{stem:{required:true,desc:"单词含(数字),如G(2)pe"},answer:{required:true,desc:"需填入的字母"},options:{required:true,min:4,max:7,desc:"候选字母4-7个"},taskDesc:{required:true,desc:"任务描述"}},imageRequired:{base:true,withImage:true},targetFromKnowledgePoint:true,maxBlankHalfWord:true,check:function(c){var issues=[],stem=c.stem||c.word||"",ans=c.answer||c.missingLetters||"";if(!stem)issues.push({field:"stem","msg":"缺少拼词题干"});if(stem&&!/[((]\d+[))]/.test(stem))issues.push({field:"stem","msg":"题干缺少(数字)占位符,如G(2)pe"});if(!ans)issues.push({field:"answer","msg":"缺少需填入的字母"});if(stem&&ans){var digits=(stem.match(/[((](\d+)[))]/)||[])[1];if(digits&&parseInt(digits)!==ans.length)issues.push({field:"answer","msg":"答案字母数("+ans.length+")与占位数字("+digits+")不一致"});}var optsRaw=c.options||c.letters||"";var opts=typeof optsRaw==="string"?optsRaw.split(/[,,]/).filter(Boolean):optsRaw;if(opts.length<4)issues.push({field:"options","msg":"候选字母不足4个"});if(opts.length>7)issues.push({field:"options","msg":"候选字母超过7个"});if(ans&&ans.length){var ansLetters=ans.split(""),letterSet=opts.map(function(l){return l.trim()});ansLetters.forEach(function(l){if(letterSet.indexOf(l)===-1)issues.push({field:"options","msg":["答案字母 '"+l+"' 不在候选项"].join(" ")});});}return issues;}},"info_sentence_building":{label:"信息组句",family:"info",hasCorrectAnswer:true,fields:{options:{required:true,min:3,max:5,desc:"短语/词组选项,3-5个,乱序"},answer:{required:true,desc:"完整句子,含大小写+标点"},hint:{required:false,desc:"辅助信息"}},imageRequired:{base:true,withImage:true},distractors:{min:1,max:2},phraseLevel:true,noCapsNoPunct:true,check:function(c){var issues=[],opts=c.options||c.choices||[],ans=c.answer||c.correctSentence||"";if(opts.length<3)issues.push({field:"options","msg":"信息组句选项至少3个(当前"+opts.length+"个)"});if(opts.length>5)issues.push({field:"options","msg":"信息组句选项最多5个(当前"+opts.length+"个)"});if(!ans)issues.push({field:"answer","msg":"缺少正确句子答案"});if(ans&&!/[A-Z]/.test(ans.charAt(0)))issues.push({field:"answer","msg":"答案句首缺少大写"});if(ans&&!/[.!?]$/.test(ans))issues.push({field:"answer","msg":"答案句末缺少标点"});opts.forEach(function(o,i){var t=typeof o==="string"?o:(o.text||o.label||"");if(t&&/[A-Z]/.test(t.charAt(0)))issues.push({field:"options","msg":"选项"+(i+1)+"有首字母大写(信息组句选项不得大写)"});if(t&&/[.!?]$/.test(t))issues.push({field:"options","msg":"选项"+(i+1)+"有句末标点(信息组句选项不得带标点)"});});return issues;}},"speaking_image":{label:"看图说话",family:"speaking",hasCorrectAnswer:true,fields:{taskTitle:{required:true},taskBackground:{required:true},taskDescription:{required:true},knowledge:{required:true},dialogueRole:{required:true},interactionQuestions:{required:true},passRules:{required:true}},imageRequired:{base:true,withImage:true},check:function(c){var issues=[];["taskTitle","taskBackground","taskDescription","knowledge","dialogueRole","interactionQuestions","passRules"].forEach(function(f){if(!c[f])issues.push({field:f,msg:"缺少必填字段: "+f});});return issues;}},"core_navigation":{label:"核心互动导览",family:"core",hasCorrectAnswer:true,fields:{taskTitle:{required:true,maxLen:10},taskBackground:{required:true,maxLen:30},taskDescription:{required:true,maxLen:20},knowledge:{required:true},dialogueRole:{required:true},roleBackground:{required:true},interactionQuestions:{required:true},roundSetting:{required:false},passRules:{required:true},exampleDialog:{required:true}},imageRequired:{base:false,withImage:true},check:function(c){var issues=[];["taskTitle","taskBackground","taskDescription","knowledge","dialogueRole","roleBackground","interactionQuestions","passRules","exampleDialog"].forEach(function(f){if(!c[f])issues.push({field:f,msg:"缺少必填字段: "+f});});if(c.taskTitle&&c.taskTitle.length>10)issues.push({field:"taskTitle","msg":["任务标题超过10字(当前"+c.taskTitle.length+"字)"].join(" ")});if(c.knowledge){var kn=c.knowledge;if(typeof kn==="string"&&!/[a-zA-Z]/.test(kn))issues.push({field:"knowledge","msg":"知识缺少英文句型"});}return issues;}},"core_reading":{label:"合作阅读",family:"core",hasCorrectAnswer:true,fields:{taskData:{required:true},sequenceData:{required:true},textData:{required:true},learningData:{required:true}},check:function(c){var issues=[];if(!c.textData||!c.textData.text||!c.textData.text.length)issues.push({field:"textData","msg":"阅读材料(textData.text)为空"});if(c.textData&&c.textData.question){c.textData.question.forEach(function(q,i){if(!q.meaning||!q.meaning.trim())issues.push({field:"textData.question","msg":"第"+(i+1)+"道阅读题缺少 meaning 标签"});if(q.optionList){q.optionList.forEach(function(opt,j){if(!opt.feedback)issues.push({field:"textData.question","msg":"第"+(i+1)+"题选项"+(j+1)+"缺少 feedback"});});}});}return issues;}},"core_listening":{label:"合作听力",family:"core",hasCorrectAnswer:true,fields:{taskData:{required:true},sequenceData:{required:true},textData:{required:true},learningData:{required:true}},check:function(c){var issues=[];if(c.textData&&(!c.textData.audio||!c.textData.audio.length))issues.push({field:"textData.audio","msg":"听力材料(textData.audio)为空"});if(c.taskData&&!c.taskData.sceneDesc)issues.push({field:"taskData.sceneDesc","msg":"缺少场景描述"});return issues;}},"core_writing":{label:"写作互动",family:"core",hasCorrectAnswer:true,fields:{taskInfo:{required:true},textInfo:{required:true},evalInfo:{required:true},studyInfo:{required:true}},check:function(c){var issues=[];if(c.textInfo&&(!c.textInfo.textList||!c.textInfo.textList.length))issues.push({field:"textInfo.textList","msg":"写作素材(textInfo.textList)为空"});if(!c.evalInfo)issues.push({field:"evalInfo","msg":"缺少写作评分配置(evalInfo)"});return issues;}}};
// ═══════════ MASTERY WEIGHTS (from knowledge-mastery-calculator) ═══════════
var MASTERY_WEIGHTS={componentTypes:{pronunciation:0.2,repeat:0.2,reading_aloud:0.2,input:0.3,choice:0.3,matching:0.3,drag:0.3,listening:0.3,output:0.5,fill_blank:0.5,sentence_building:0.5,speaking:0.5,writing:0.5,image_speaking:0.5},repetitionMultiplier:[1.0,1.0,1.5,2.0,2.0,2.5],masteryThresholds:{mastered:80,basic:60,partial:40}};
// ═══════════ NEGATIVE WORDS (from MEMORY.md 价值观导向规范) ═══════════
var NEGATIVE_WORDS=["stupid","ugly","fat","dumb","idiot","loser","hate","terrible","awful","horrible","worst","failure","useless","hopeless"];
// ═══════════ THIRD-PERSON SINGULAR SUBJECTS ═══════════
var THIRD_SINGULAR=["he","she","it"];
// ═══════════ Utils ═══════════
function ew(t){return t?t.toLowerCase().replace(/[^a-z\s'-]/g,' ').split(/\s+/).filter(function(w){return w.length>1}):[]}
function wc(t){return t?t.split(/\s+/).length:0}
function clamp(v,lo,hi){return Math.max(lo,Math.min(hi,v))}
function avg(arr){return arr.length?arr.reduce(function(a,b){return a+b},0)/arr.length:0}
function escReg(s){return s.replace(/[-\/\\^$*+?.()|[\]{}]/g,'\\$&')}
// ═══════════ QUALITY SCORERS (v3 + v4 extensions) ═══════════
// 1. Vocab Alignment (0-100, higher=more over-level issues)
function scoreVocabAlignment(keyPreview,lvl){
var targets=keyPreview||[],wl=W[lvl||'L1']||W.L1,bm=BM[lvl||'L1']||BM.L1;
if(!targets.length)return{score:0,label:'无目标词',details:[],totalCount:0,overLevelCount:0,interpretation:'无目标词数据'};
var scores=[],details=[],overCount=0;
targets.forEach(function(w){
var lo=(w||'').toLowerCase().trim();if(!lo)return;
var v=wl[lo];if(v){scores.push(0);details.push({word:w,status:'in_level',diff:v.diff||1,msg:'"'+w+'" 在词库内 ✓'});}
else{
var l2w=W.L2[lo];if(l2w){scores.push(50);details.push({word:w,status:'above_level',diff:l2w.diff||2,msg:'"'+w+'" 是L2词 ⚠️'});overCount++;}
else{scores.push(100);details.push({word:w,status:'out_of_scope',diff:99,msg:'"'+w+'" 超纲 ✗'});overCount++;}
}
});
var sc=avg(scores),above=details.filter(function(d){return d.status==='above_level'||d.status==='out_of_scope'}).length;
var interp=sc===0?'全部在词库内 ✓':sc<20?'个别超纲':sc<50?'部分超纲':'严重超纲';
return{score:Math.round(sc),label:'词汇匹配度',details:details,totalCount:targets.length,overLevelCount:above,interpretation:interp};
}
// 2. Sentence Complexity (0-100, higher=too complex)
function scoreSentenceComplexity(dialogs,lvl){
var lines=(dialogs||[]).filter(function(l){return typeof l==='string'&&l.trim()}),bm=BM[lvl||'L1']||BM.L1;
if(!lines.length)return{score:0,label:'无台词',details:[],interpretation:'无法评分:缺少对话台词'};
var scores=[],details=[],maxL=bm.sentenceLength.max,idealL=bm.sentenceLength.ideal;
lines.forEach(function(line){
var n=wc(line);scores.push(n>maxL?100:Math.round(Math.abs(n-idealL)/idealL*60));
if(n>maxL)details.push({line:line,words:n,status:'too_long',msg:n+'词 → 超过上限'+maxL+'词'});
});
var over=details.length,total=lines.length,sc=Math.round(avg(scores));
var interp=over===0?'句长全部合规 ✓':over/total<0.2?'少数偏长 ('+over+'/'+total+')':'句长问题较多 ('+over+'/'+total+')';
return{score:sc,label:'句子复杂度',overCount:over,totalCount:total,overRate:Math.round(over/total*100),maxLineLength:maxL,interpretation:interp};
}
// 3. Knowledge Density
function scoreKnowledgeDensity(keyPreview,dialogRounds,lvl){
var bm=BM[lvl||'L1']||BM.L1,tc=(keyPreview||[]).length,dr=Math.max(dialogRounds||1,1);
var ratio=tc/dr,idealRatio=bm.targetWordsPerRound/bm.idealRounds*4;
var sc=ratio>1?Math.round(Math.min(ratio/idealRatio*100,100)):Math.round(ratio/idealRatio*60);
var interp=sc<30?'知识密度偏低 ('+tc+'词/'+dr+'轮),学习效率可提升':sc<55?'知识密度适中 ('+tc+'词/'+dr+'轮),节奏合理 ✓':sc<75?'知识密度偏高 ('+tc+'词/'+dr+'轮),学生可能吸收不足':'知识密度过高 ('+tc+'词/'+dr+'轮),建议拆分或减少目标';
return{score:sc,label:'知识密度',targetCount:tc,dialogRounds:dr,ratio:Math.round(ratio*100)/100,idealRatio:Math.round(idealRatio*100)/100,interpretation:interp};
}
// 4. Knowledge Exposure
function scoreKnowledgeExposure(keyPreview,allDialogs,lvl){
var targets=keyPreview||[],dialogs=allDialogs||[],bm=BM[lvl||'L1']||BM.L1;
if(!targets.length||!dialogs.length)return{score:0,label:'无数据',details:[],interpretation:'无法评分:缺少目标词或台词数据'};
var dText=dialogs.join(' ').toLowerCase(),scores=[],details=[];
targets.forEach(function(w){
var lo=(w||'').toLowerCase().trim();if(!lo)return;
var re=new RegExp('\\b'+escReg(lo)+'\\b','g');
var cnt=(dText.match(re)||[]).length;
var sc=cnt===0?0:cnt===1?30:cnt===2?70:cnt>=bm.targetExposure.ideal?100:Math.round(70+(cnt-2)/(bm.targetExposure.ideal-2)*30);
scores.push(sc);
details.push({word:w,count:cnt,score:sc,status:cnt===0?'zero':cnt===1?'low':cnt===2?'moderate':'good',msg:'"'+w+'" 出现'+cnt+'次'+(cnt===0?' ⚠️ 零暴露':cnt=90?'全部目标词曝光充分 ✓':ascore>=60?'多数目标词曝光良好,'+zeroCnt+'个零暴露':ascore>=30?zeroCnt+'个目标词零暴露,'+details.filter(function(d){return d.status==='low'}).length+'个曝光不足':'知识点严重曝光不足,'+zeroCnt+'个目标词完全未出现';
return{score:ascore,label:'知识点曝光度',details:details,zeroExposureCount:zeroCnt,lowExposureCount:details.filter(function(d){return d.status==='low'}).length,perfectExposureCount:details.filter(function(d){return d.status==='good'}).length,idealExposure:bm.targetExposure.ideal,interpretation:interp};
}
// 5. Content Coverage
function scoreContentCoverage(summary,lvl){
var bm=BM[lvl||'L1']||BM.L1,s=summary||{},score=0;
if(s.keyPreview&&s.keyPreview.length)score+=25;
if(s.dialogRounds&&s.dialogRounds>=bm.dialogRounds.min)score+=25;
if(s.dialogLines&&s.dialogLines.length>=4)score+=25;
if(s.realContent&&s.realContent.dialogs&&s.realContent.dialogs.length>=4)score+=25;
var interp=score>=75?'内容结构完整 ✓':score>=50?'基本完整,可补充':'内容结构薄弱,缺少关键要素';
return{score:score,label:'内容覆盖度',details:{hasKeyPreview:!!(s.keyPreview&&s.keyPreview.length),hasDialogRounds:!!(s.dialogRounds&&s.dialogRounds>=bm.dialogRounds.min),hasDialogLines:!!(s.dialogLines&&s.dialogLines.length>=4)},interpretation:interp};
}
// ═══════════ v4 NEW DIMENSION SCORERS ═══════════
// 6. Component Type Compliance (from dialogue-*/info-* config skills)
// Checks whether a component's config matches the rules for its type
function scoreComponentCompliance(component,level){
var l=level||'L1',c=component||{};
if(!c||!c.type&&!c.cType)return{score:null,label:'组件合规',skip:true,interpretation:'缺少组件类型信息,跳过检测'};
var ct=(c.type||c.cType||'').toLowerCase().replace(/[\s-]/g,'_'),rules=COMPONENT_RULES[ct];
if(!rules)return{score:null,label:'组件合规',skip:true,type:ct,interpretation:'组件类型 "'+ct+'" 未在规则库中注册,跳过检测'};
var issues=rules.check(c),maxIssues=10;
var sc=issues.length===0?0:Math.min(Math.round(issues.length/maxIssues*100),100);
var interp=issues.length===0?'组件配置完全合规 ✓':issues.length<=2?'少量配置问题 ('+issues.length+'个)':'配置问题较多 ('+issues.length+'个),需整改';
return{score:sc,label:'组件合规性',componentType:ct,typeLabel:rules.label,family:rules.family,issues:issues,issueCount:issues.length,interpretation:interp};
}
// 7. Config Field Integrity (from audit_l1_config 7 auto checks)
// Validates JSON structure, field consistency, classification correctness
function scoreConfigIntegrity(component,level){
var l=level||'L1',c=component||{},issues=[];
// 7.1 basicInfo/config/usageInfo completeness
var requiredTop=["type","cType","id","cId","title","taskTitle"];
var found=requiredTop.filter(function(k){return c[k]!==undefined&&c[k]!==null&&c[k]!=='';});
if(found.length<2)issues.push({check:"字段完整性","msg":"核心字段缺失(type/cType/id/title等),已找到: "+found.join(', ')});
// 7.2 Classification swap detection (cambridgeLevel ↔ cefrLevel)
if(c.cambridgeLevel&&c.cefrLevel){
var camLevels=["YLE","Starters","Movers","Flyers","KET","PET","FCE"];
var cefrLevels=["Pre-A1","A1","A2","B1","B2","C1","C2"];
if(cefrLevels.indexOf(c.cambridgeLevel)>=0&&camLevels.indexOf(c.cefrLevel)>=0)
issues.push({check:"分类互换","msg":"cambridgeLevel="+c.cambridgeLevel+"(应为剑桥等级) ↔ cefrLevel="+c.cefrLevel+"(应为CEFR等级),疑似值互换"});
}
// 7.3 JSON structure integrity (options answer range check)
if(c.options&&c.answer!==undefined){
var ans=parseInt(c.answer);
if(!isNaN(ans)&&c.options.length&&(ans<0||ans>=c.options.length))
issues.push({check:"答案越界","msg":"answer="+ans+" 超出 options 范围 [0,"+(c.options.length-1)+"]"});
}
// 7.4 Word bank ↔ answer consistency (sentenceStructureSort-like)
if(c.wordBank&&c.answerSentence){
var built=c.wordBank.join(' ').toLowerCase().replace(/[^a-z\s]/g,'');
var expected=c.answerSentence.toLowerCase().replace(/[^a-z\s]/g,'');
if(built!==expected)
issues.push({check:"单词库一致性","msg":"单词库拼出句子与答案不一致"});}
// 7.5 Coverage: all mandatory fields non-empty
var requiredFields=["id","cType","title","taskDesc","kpInfo"];
requiredFields.forEach(function(f){
if(c[f]===undefined||c[f]===null||(typeof c[f]==='string'&&!c[f].trim()))
issues.push({check:"覆盖性",msg:"必填字段 '"+f+"' 为空"});});
// 7.6 Chinese ↔ JSON field consistency
if(c.title_zh&&!c.title)issues.push({check:"中英一致性","msg":"有中文标题但无 title 字段"});
if(c.desc_zh&&!c.taskDesc)issues.push({check:"中英一致性","msg":"有中文描述但无 taskDesc 字段"});
// 7.7 component type registration check
if(c.cType&&!COMPONENT_RULES[c.cType.toLowerCase().replace(/[\s-]/g,'_')])
issues.push({check:"类型注册","msg":"cType '"+c.cType+"' 未在规则库中注册"});
var sc=issues.length===0?0:Math.min(Math.round(issues.length/7*100),100);
var interp=issues.length===0?'字段完整性全部通过 ✓':issues.length<=2?'少量字段问题 ('+issues.length+'个)':'字段完整性问题较多 ('+issues.length+'个)';
return{score:sc,label:'字段完整性',issues:issues,issueCount:issues.length,interpretation:interp};
}
// 8. Knowledge Mastery Prediction (from knowledge-mastery-calculator)
// Predicts expected mastery rate given component exposure patterns
function scoreMasteryPrediction(componentExposures,level){
var exps=componentExposures||[],l=level||'L1';
if(!exps.length)return{score:null,label:'掌握度预测',skip:true,interpretation:'缺少组件曝光数据,跳过预测'};
var totalScore=0,fullScore=0,details=[];
exps.forEach(function(exp,i){
var ct=(exp.componentType||exp.type||'input').toLowerCase().replace(/[\s-]/g,'_');
var w=MASTERY_WEIGHTS.componentTypes[ct]||MASTERY_WEIGHTS.componentTypes.input;
var occIdx=Math.min(i,MASTERY_WEIGHTS.repetitionMultiplier.length-1);
var m=MASTERY_WEIGHTS.repetitionMultiplier[occIdx];
var passed=exp.passed||exp.perfect||exp.success||1;
var s=passed*(w*m);
totalScore+=s;fullScore+=w*m;
details.push({componentType:ct,occurrence:i+1,weight:w,multiplier:m,passed:!!passed,score:s,typeLabel:exp.typeLabel||ct});
});
var rate=fullScore>0?Math.round(totalScore/fullScore*100):0;
var thresh=MASTERY_WEIGHTS.masteryThresholds;
var grade=rate>=thresh.mastered?'熟练掌握':rate>=thresh.basic?'基本掌握':rate>=thresh.partial?'部分掌握':'未掌握';
return{score:100-rate,label:'掌握度预测',masteryRate:rate,grade:grade,totalScore:totalScore,fullScore:fullScore,details:details,interpretation:'预测掌握率 '+rate+'% → '+grade};
}
// 9. Format Quality (from text output standardization rules)
function scoreFormatQuality(component,level){
var c=component||{},issues=[],l=level||'L1';
// 9.1 Title format check
var title=c.title||c.taskTitle||"";
if(title&&/-/.test(title))issues.push({check:"标题格式","msg":"标题含 '-',应用中文括号替代: "+title});
if(title&&/[a-zA-Z][\u4e00-\u9fa5]|[\u4e00-\u9fa5][a-zA-Z]/.test(title))
issues.push({check:"标题格式","msg":"标题中英文间缺少空格: "+title});
// 9.2 Markdown check
var textFields=[c.stem,c.sentence,c.interactiveContent,c.taskDesc,c.sceneDesc,c.roleBackground,c.taskBackground];
textFields.forEach(function(t,i){
if(t&&typeof t==='string'&&(/[*_]{1,2}/.test(t)||/^[#>]/.test(t)))
issues.push({check:"Markdown","msg":"文本字段含Markdown标记: '"+t.substring(0,50)+"...'"});});
// 9.3 Punctuation check (full-width in English context)
var engFields=[c.stem,c.sentence,c.interactiveContent,c.answer,c.correctSentence];
engFields.forEach(function(t){
if(t&&typeof t==='string'&&/[,。!?]/.test(t)&&/[a-zA-Z]/.test(t))
issues.push({check:"标点混用","msg":"英文文本含中文全角标点: '"+t.substring(0,40)+"...'"});});
// 9.4 Non-standard punctuation
engFields.forEach(function(t){
if(t&&typeof t==='string'&&/~/.test(t))
issues.push({check:"标点规范","msg":"含非标准标点 '~': '"+t.substring(0,40)+"...'"});});
engFields.forEach(function(t){
if(t&&typeof t==='string'&&/!!!|!!/.test(t))
issues.push({check:"标点规范","msg":"含过度感叹号 '!!!' 或 '!!': '"+t.substring(0,40)+"...'"});});
// 9.5 British spelling check
engFields.forEach(function(t){
if(!t||typeof t!=='string')return;
var words=t.split(/\s+/);words.forEach(function(w){
var clean=w.replace(/[^a-zA-Z]/g,''),lower=clean.toLowerCase();
if(BRITISH_SPELLING[lower])issues.push({check:"英式拼写","msg":"检测到美式拼写 '"+clean+"' → 应为 '"+BRITISH_SPELLING[lower]+"'"});
});});
// 9.6 Negative self-evaluation check
var allText=(c.stem||"")+" "+(c.sentence||"")+" "+(c.interactiveContent||"")+" "+(c.taskDesc||"")+" "+(c.sceneDesc||"");
var lowerAll=allText.toLowerCase();NEGATIVE_WORDS.forEach(function(w){
if(lowerAll.indexOf(w)>=0)issues.push({check:"价值观","msg":"含负面评价词汇 '"+w+"'(避免负面评价自己或他人)"});});
// 9.7 Title Chinese paren convention
if(title&&/-1|-2|-3/.test(title))issues.push({check:"标题规范","msg":"标题用了'-1'编号,应改为中文括号'(一)'"});
var sc=Math.min(Math.round(issues.length/8*100),100);
var interp=issues.length===0?'格式规范全部通过 ✓':issues.length<=2?'少量格式问题 ('+issues.length+'个)':'格式问题较多 ('+issues.length+'个)';
return{score:sc,label:'格式规范',issues:issues,issueCount:issues.length,interpretation:interp};
}
// 10. Grammar Issue Detection (from audit_l1_config check 5 + dialogue rules)
function scoreGrammarIssues(component,level){
var c=component||{},issues=[],l=level||'L1';
// 10.1 Third-person singular check
var stem=c.stem||c.sentence||c.interactiveContent||"",stemLower=stem.toLowerCase();
var hasThirdSubj=THIRD_SINGULAR.some(function(s){return new RegExp('\\b'+s+'\\b').test(stemLower);});
if(c.dialogueRole){var roleLower=c.dialogueRole.toLowerCase();
if(THIRD_SINGULAR.indexOf(roleLower)>=0)hasThirdSubj=true;}
if(hasThirdSubj){
var words=stemLower.split(/\s+/),hasNeed=words.indexOf("need")>=0,hasNeeds=words.indexOf("needs")>=0;
if(hasNeed&&!hasNeeds)
issues.push({check:"三单语法","msg":"三单主语但使用 'need' 而非 'needs': '"+stem+"'"});
}
// 10.2 Subject-verb agreement
if(stemLower.match(/\b(he|she|it|Otis|Maeve|Mum|Dad)\b.*\b(go|do|have|make|say|tell|like|play|run|come|eat|sing|want|get|put|see|give|try|look|use|take)\b/)&&
!stemLower.match(/\b(goes|does|has|makes|says|tells|likes|plays|runs|comes|eats|sings|wants|gets|puts|sees|gives|tries|looks|uses|takes)\b/))
issues.push({check:"主谓一致","msg":"疑似三单主语 + 动词原形: '"+stem+"'"});
// 10.3 Double negation in L1
if(l==='L1'){
var negWords=["don't","doesn't","no","not","never"];
var negCount=negWords.filter(function(w){return stemLower.indexOf(w)>=0;}).length;
if(negCount>=2)issues.push({check:"双重否定","msg":"L1级别含双重否定(难度不适配): '"+stem+"'"});}
var sc=Math.min(Math.round(issues.length/3*100),100);
var interp=issues.length===0?'语法检测通过 ✓':'检测到 '+issues.length+' 个语法问题';
return{score:sc,label:'语法检测',issues:issues,issueCount:issues.length,interpretation:interp};
}
// ═══════════ BEHAVIORAL CORRELATION ═══════════
function correlateBehavioral(qualityScores,item,lvl){
var p=Number(item.perfect)||0,o=Number(item.oops)||0,g=Number(item.good)||0,vs=qualityScores.vocabAlignment||{},insights=[];
if(!p&&!o&&!g)return{insights:[],summary:'无行为数据,无法关联分析'};
if(vs.overLevelCount>0&&p<80)
insights.push({dimension:'vocabAlignment',correlation:'negative',strength:vs.overLevelCount/vs.totalCount>0.3?'strong':'moderate',
insight:'词汇匹配度低('+vs.score+'分):'+vs.overLevelCount+'/'+vs.totalCount+'词超纲,可能解释Perfect率'+p+'%偏低。超纲词:'+vs.details.filter(function(d){return d.status!=='in_level'}).map(function(d){return d.word}).join('、'),
action:'建议检查并替换超纲词汇,确保在L1/L2词库范围内'});
var ks=qualityScores.knowledgeDensity||{};
if(ks.score>70&&p<70)
insights.push({dimension:'knowledgeDensity',correlation:'negative',strength:'strong',
insight:'知识密度过高('+ks.score+'分):'+ks.targetCount+'个目标词/'+ks.dialogRounds+'轮对话,学生吸收压力大,Perfect率'+p+'%与此相关',
action:'建议减少目标词数或增加对话轮数,降低单轮知识密度'});
var es=qualityScores.knowledgeExposure||{};
if(es.zeroExposureCount>0&&p<80)
insights.push({dimension:'knowledgeExposure',correlation:'negative',strength:es.zeroExposureCount>1?'strong':'moderate',
insight:'知识点曝光不足('+es.score+'分):'+es.zeroExposureCount+'个目标词零暴露,学生未在语境中充分接触目标语言',
action:'建议在对话中增加目标词的显性出现,确保每个目标词至少出现2次'});
// v4 extension: component compliance → behavior correlation
var cc=qualityScores.componentCompliance||{};
if(cc.issueCount>0&&p<80)
insights.push({dimension:'componentCompliance',correlation:'negative',strength:cc.issueCount>3?'strong':'moderate',
insight:'组件合规问题('+cc.issueCount+'个):配置不规范可能影响用户体验,Perfect率'+p+'%与此相关',
action:'建议修复组件配置中的合规问题'});
// v4 extension: format quality → Oops correlation
var fq=qualityScores.formatQuality||{};
if(fq.issueCount>2&&o>=10)
insights.push({dimension:'formatQuality',correlation:'negative',strength:'moderate',
insight:'格式规范问题('+fq.issueCount+'个):文本质量问题可能增加学生困惑,Oops率'+o+'%相关',
action:'建议修复格式规范问题'});
var gi=qualityScores.grammarIssues||{};
if(gi.issueCount>0&&o>=5)
insights.push({dimension:'grammarIssues',correlation:'negative',strength:'moderate',
insight:'语法问题('+gi.issueCount+'个):语法错误可能导致学生操作困惑,Oops率'+o+'%相关',
action:'建议修复语法错误'});
return{insights:insights,summary:insights.length+'条行为关联洞察'};
}
// ═══════════ COMPONENT COMPARISON ═══════════
function compareComponents(compA,compB,lvl){
function qs(c){return evaluate(c.summary,c.item,lvl).qualityScores;}
var a=qs(compA),b=qs(compB),diff={};
['vocabAlignment','sentenceComplexity','knowledgeDensity','knowledgeExposure','contentCoverage','componentCompliance','configIntegrity','formatQuality','grammarIssues'].forEach(function(k){
if(a[k]&&b[k]&&a[k].score!==undefined&&b[k].score!==undefined)
diff[k]={a:a[k].score,b:b[k].score,delta:b[k].score-a[k].score,direction:b[k].score>a[k].score?'B优于A':a[k].score>b[k].score?'A优于B':'持平'};
});
return{componentA:{id:compA.item&&compA.item.cId||'',type:compA.item&&compA.item.cType||''},componentB:{id:compB.item&&compB.item.cId||'',type:compB.item&&compB.item.cType||''},diffs:diff};
}
// ═══════════ RISK ANALYSIS ═══════════
function analyzeRisks(qualityScores,item,lvl){
var flags=[],p=Number(item.perfect)||0,o=Number(item.oops)||0;
// v3 risk flags
if(qualityScores.vocabAlignment&&qualityScores.vocabAlignment.score>50)
flags.push({risk:'vocab_overreach',severity:qualityScores.vocabAlignment.score>80?'high':'medium',
detail:qualityScores.vocabAlignment.overLevelCount+'/'+qualityScores.vocabAlignment.totalCount+'词超纲',impact:'超纲词汇 → 学习困难 → Perfect↓'});
if(qualityScores.sentenceComplexity&&qualityScores.sentenceComplexity.overRate>25)
flags.push({risk:'complex_sentences',severity:qualityScores.sentenceComplexity.overRate>50?'high':'medium',
detail:qualityScores.sentenceComplexity.overCount+'/'+qualityScores.sentenceComplexity.totalCount+'句偏长',impact:'句子过长 → 阅读困难 → Perfect↓'});
if(qualityScores.knowledgeDensity&&qualityScores.knowledgeDensity.score>70)
flags.push({risk:'over_dense',severity:qualityScores.knowledgeDensity.score>85?'high':'medium',
detail:qualityScores.knowledgeDensity.targetCount+'词/'+qualityScores.knowledgeDensity.dialogRounds+'轮',impact:'知识密度过高 → 学生吸收困难 → Perfect↓'});
if(qualityScores.contentCoverage&&qualityScores.contentCoverage.score<60)
flags.push({risk:'thin_content',severity:qualityScores.contentCoverage.score<40?'high':'medium',
detail:'内容完整度仅'+qualityScores.contentCoverage.score+'分',impact:'缺少关键教学环节 → 教学效果难以保证'});
// v4 extension risk flags
var cc=qualityScores.componentCompliance||{},ci=qualityScores.configIntegrity||{},fq=qualityScores.formatQuality||{},gi=qualityScores.grammarIssues||{},mp=qualityScores.masteryPrediction||{};
if(cc.issueCount>=5)flags.push({risk:'component_noncompliant',severity:'high',detail:cc.issueCount+'个合规问题',impact:'组件配置严重不规范 → 影响交互体验'});
if(ci.issueCount>=3)flags.push({risk:'config_incomplete',severity:ci.issueCount>=5?'high':'medium',detail:ci.issueCount+'个字段完整性问题',impact:'配置字段缺失 → 可能导致运行时错误'});
if(fq.issueCount>=4)flags.push({risk:'format_quality',severity:'medium',detail:fq.issueCount+'个格式规范问题',impact:'文本质量不达标 → 影响学生理解'});
if(gi.issueCount>=2)flags.push({risk:'grammar_error',severity:gi.issueCount>=3?'high':'medium',detail:gi.issueCount+'个语法问题',impact:'语法错误 → 错误语言输入'});
if(mp.masteryRate!==undefined&&mp.masteryRate=10)flags.push({risk:'critical_performance',severity:'high',detail:'Perfect='+p+'%/Oops='+o+'%',impact:'关键内容组件表现严重不达标,需优先排查'});
else if(p<70)flags.push({risk:'low_perfect',severity:'medium',detail:'Perfect='+p+'%',impact:'学习吸收不足,建议复核内容质量和难度'});
else if(o>=10)flags.push({risk:'high_oops',severity:'medium',detail:'Oops='+o+'%',impact:'操作或理解阻塞,建议复核交互设计和内容清晰度'});
return{flags:flags,severityCounts:{high:flags.filter(function(f){return f.severity==='high'}).length,medium:flags.filter(function(f){return f.severity==='medium'}).length},summary:flags.length+'个风险项('+flags.filter(function(f){return f.severity==='high'}).length+'高/'+flags.filter(function(f){return f.severity==='medium'}).length+'中)'};
}
// ═══════════ MAIN API ═══════════
function evaluate(summary,item,lvl,options){
var l=lvl||'L1',s=summary||{},it=item||{},opts=options||{};
// Merge dialogs from both sources
var allDialogs=(s.realContent&&s.realContent.dialogs)||[];
if(!allDialogs.length&&s.dialogLines)allDialogs=s.dialogLines.filter(function(l){return typeof l==='string'}).map(function(l){return l});
var qs={};
// v3 dimensions (always scored)
qs.vocabAlignment=scoreVocabAlignment(s.keyPreview,l);
qs.sentenceComplexity=scoreSentenceComplexity(allDialogs,l);
qs.knowledgeDensity=scoreKnowledgeDensity(s.keyPreview,s.dialogRounds,l);
qs.knowledgeExposure=scoreKnowledgeExposure(s.keyPreview,allDialogs,l);
qs.contentCoverage=scoreContentCoverage(s,l);
// v4 dimensions (scored when data available)
if(opts.component||s.component||it.componentType||it.cType)
qs.componentCompliance=scoreComponentCompliance(opts.component||s.component||{type:it.cType||it.componentType,title:s.title||it.title,stem:s.stem,options:it.options||s.options,answer:it.answer||s.answer,taskDesc:s.taskDesc||it.taskDesc,requirement:it.requirement||s.requirement,feedback:it.feedback||s.feedback,wordBank:s.wordBank,answerSentence:s.answerSentence,readingSentence:s.readingSentence||s.sentence,dialogueRole:s.dialogueRole||it.dialogueRole,knowledge:s.knowledge||it.knowledge,taskBackground:s.taskBackground,id:s.id||it.cId||it.componentId},l);
if(opts.component||s.component||s.id||it.cId)
qs.configIntegrity=scoreConfigIntegrity(opts.component||s.component||{id:s.id||it.cId||it.componentId,cType:it.cType||it.componentType,title:s.title||it.title,taskDesc:s.taskDesc,cambridgeLevel:s.cambridgeLevel,cefrLevel:s.cefrLevel,options:it.options,answer:it.answer,wordBank:s.wordBank,answerSentence:s.answerSentence,title_zh:s.title_zh,desc_zh:s.desc_zh},l);
if(opts.componentExposures&&opts.componentExposures.length)
qs.masteryPrediction=scoreMasteryPrediction(opts.componentExposures,l);
if(opts.component||s.component||s.title||it.title)
qs.formatQuality=scoreFormatQuality(opts.component||s.component||{title:s.title||it.title,taskTitle:s.taskTitle||it.taskTitle,stem:s.stem,interactiveContent:s.interactiveContent,sentence:s.sentence,taskDesc:s.taskDesc,sceneDesc:s.sceneDesc,roleBackground:s.roleBackground,taskBackground:s.taskBackground,answer:s.answer||it.answer,correctSentence:s.correctSentence||s.answer},l);
if(opts.component||s.component||s.stem||s.sentence)
qs.grammarIssues=scoreGrammarIssues(opts.component||s.component||{stem:s.stem,dialogueRole:s.dialogueRole||it.dialogueRole,sentence:s.sentence,interactiveContent:s.interactiveContent},l);
// Weighted overall score (expanded for v4)
// Lower = better (0=perfect, 100=worst)
var weights={vocabAlignment:0.20,sentenceComplexity:0.10,knowledgeDensity:0.08,knowledgeExposure:0.20,contentCoverage:0.07,componentCompliance:0.10,configIntegrity:0.10,masteryPrediction:0.05,formatQuality:0.05,grammarIssues:0.05};
var posMetrics={knowledgeExposure:true,contentCoverage:true};
var overall=0,wsum=0;
Object.keys(weights).forEach(function(k){
if(qs[k]&&qs[k].score!==undefined&&qs[k].score!==null&&!qs[k].skip){
var sc=posMetrics[k]?(100-qs[k].score):qs[k].score;
overall+=sc*weights[k];wsum+=weights[k];
}
});
// Renormalize weights for available dimensions
if(wsum>0)overall=Math.round(overall/wsum);else overall=null;
// Behavioral boost
var p=Number(it.perfect)||0,o=Number(it.oops)||0;
if(p>0&&p<60&&overall!==null)overall=Math.round(overall*0.7+15);
if(o>15&&overall!==null)overall=Math.round(overall*0.7+15);
var bi=correlateBehavioral(qs,it,l);
var ra=analyzeRisks(qs,it,l);
return{
version:VERSION,
level:l,
componentType:it.cType||it.type||'',
componentId:it.cId||'',
qualityScores:qs,
overallQualityScore:overall,
overallLabel:overall===null?'无法计算':overall<15?'优(内容质量高)':overall<30?'良(质量较好)':overall<50?'中(有提升空间)':'差(需优化)',
behavioralInsights:bi,
riskAnalysis:ra,
timestamp:new Date().toISOString()
};
}
function score(summary,lvl){return evaluate(summary,null,lvl).qualityScores;}
function benchmarks(lvl){return BM[lvl||'L1']||BM.L1;}
function listComponentTypes(){return Object.keys(COMPONENT_RULES).map(function(k){return{type:k,label:COMPONENT_RULES[k].label,family:COMPONENT_RULES[k].family};});}
function getComponentRules(type){return COMPONENT_RULES[type]||null;}
// ── Export ──
g.PedagogyRules={VERSION:VERSION,
evaluate:evaluate,score:score,benchmarks:benchmarks,compare:compareComponents,
// v3 scorers
scoreVocabAlignment:scoreVocabAlignment,scoreSentenceComplexity:scoreSentenceComplexity,
scoreKnowledgeDensity:scoreKnowledgeDensity,scoreKnowledgeExposure:scoreKnowledgeExposure,
scoreContentCoverage:scoreContentCoverage,
// v4 scorers (NEW)
scoreComponentCompliance:scoreComponentCompliance,scoreConfigIntegrity:scoreConfigIntegrity,
scoreMasteryPrediction:scoreMasteryPrediction,scoreFormatQuality:scoreFormatQuality,
scoreGrammarIssues:scoreGrammarIssues,
// v4 utilities
listComponentTypes:listComponentTypes,getComponentRules:getComponentRules,correlateBehavioral:correlateBehavioral,analyzeRisks:analyzeRisks,
// Data (NEW: BRITISH_SPELLING, COMPONENT_RULES, MASTERY_WEIGHTS)
WORD_LISTS:W,PATTERNS:P,BENCHMARKS:BM,BRITISH_SPELLING:BRITISH_SPELLING,COMPONENT_RULES:COMPONENT_RULES,MASTERY_WEIGHTS:MASTERY_WEIGHTS,NEGATIVE_WORDS:NEGATIVE_WORDS
};
console.log('[PedagogyRules v4] L1 words:'+Object.keys(W.L1).length+' L2 words:'+Object.keys(W.L2).length+' L1 pat:'+P.L1.length+' L2 pat:'+P.L2.length+' component types:'+listComponentTypes().length+' spelling map:'+Object.keys(BRITISH_SPELLING).length);
})(typeof window!=='undefined'?window:this);