import fs from 'node:fs' const read=p=>fs.readFileSync(p,'utf8') const failures=[];const check=(ok,msg)=>{if(!ok)failures.push(msg)} for(const [file,label] of [ ['packages/kbx-ui/src/components/KbxFastEntryPage.vue','T04'], ['packages/kbx-ui/src/components/KbxMasterDetailPage.vue','T05'], ['packages/kbx-ui/src/components/KbxQueuePage.vue','T06'], ['packages/kbx-ui/src/components/KbxReconcilePage.vue','T07'], ['packages/kbx-ui/src/components/KbxImportPage.vue','T08'], ]){ const src=read(file) for(const token of ['KbxProblemFeedback','problem?:','problemActionAllowlist','retryProblem','dismissProblem'])check(src.includes(token),`${label} actionable problem contract missing: ${token}`) } const work=read('packages/kbx-ui/src/components/KbxWorkQueuePage.vue') for(const token of [':problem="problem"','@retry-problem','@dismiss-problem'])check(work.includes(token),`KbxWorkQueuePage problem pass-through missing: ${token}`) const fast=read('apps/web/src/modules/erp/item-prices/useItemPriceFastEntry.ts') for(const token of ['const problem=ref(null)',"failedAction:'save'|null",'retryProblem','dismissProblem'])check(fast.includes(token),`T04 real Vue recovery missing: ${token}`) const queue=read('apps/web/src/modules/common/operations/OperationsQueuePage.vue') for(const token of ['isKbxProblem','runProblemAware',':problem="problem"','@retry-problem="retryProblem"'])check(queue.includes(token),`T06 real Vue recovery missing: ${token}`) const rec=read('apps/web/src/modules/common/reconcile/ReconcilePage.vue') for(const token of ['isKbxProblem','runProblemAware',':problem="problem"','@retry-problem="retryProblem"'])check(rec.includes(token),`T07 real Vue recovery missing: ${token}`) const imp=read('apps/web/src/modules/oms/orders/import/useOrderExcelImport.ts') for(const token of ['isKbxProblem','runProblemAware','problem,','retryProblem','dismissProblem'])check(imp.includes(token),`T08 real Vue recovery missing: ${token}`) const ref=read('apps/web/fe-reference/kbx-fe.js') for(const token of ['inventoryVisibleItems','executeInventorySearch','queueVisibleRows','executeQueueSearch','reconcileVisibleRows','executeReconcileSearch','type="file"','applyImportFile(file)','20*1024*1024'])check(ref.includes(token),`Reference completion missing: ${token}`) for(const forbidden of ["toast('재고현황을 조회했습니다.')","toast('작업 Queue를 조회했습니다.')","toast('대사 결과를 조회했습니다.')","state.importFileName='orders_20260811.xlsx'"])check(!ref.includes(forbidden),`Reference still contains fake interaction: ${forbidden}`) const css=read('apps/web/fe-reference/kbx-fe.css') check(css.includes('.import-steps{display:grid;grid-template-columns:repeat(6,1fr);'),'T08 six-step visual grid must use six columns') const feedback=read('packages/kbx-ui/src/components/KbxProblemFeedback.vue') check(feedback.includes("problem.type === 'validation'")&&feedback.includes('problem.errors.slice(0,3)'),'Problem feedback must summarize validation problems when template has no field-specific surface') if(failures.length){console.error('FE template completion v48 validation failed:');for(const f of failures)console.error(`- ${f}`);process.exit(1)} console.log('FE template completion v48 PASS: T04-T08 problem recovery + real T05-T08 Reference search/file interactions.')