import fs from 'node:fs' const failures=[] const read=path=>fs.readFileSync(path,'utf8') const requireTokens=(path,tokens)=>{ const text=read(path) for(const token of tokens)if(!text.includes(token))failures.push(`${path} missing ${token}`) return text } const grid=requireTokens('packages/kbx-ui/src/components/KbxDataGrid.vue',[ "mode:'multiRow'", 'checkboxes:true', 'headerCheckbox:true', 'syncSelectionState', 'gridErrors', 'focusNextEditableCell', 'selectRowByKey', 'defineExpose', ]) if(grid.includes("row-selection=\"selection==='multiple'?'multiple'"))failures.push('KbxDataGrid still uses deprecated string rowSelection configuration') const lookup=requireTokens('packages/kbx-ui/src/components/KbxLookup.vue',[ 'focusNextControl', 'dialogWasOpen', '`${label} 코드`', '`${label} 검색`', ]) if(lookup.includes('aria-label="코드"'))failures.push('KbxLookup exposes ambiguous duplicate code labels') requireTokens('packages/kbx-ui/src/shell/KbxUnsavedChangesDialog.vue',[ "event.key === 'Escape'", "event.key !== 'Tab'", 'restoreFocus', 'aria-describedby="unsaved-detail"', ]) const orderList=requireTokens('apps/web/src/modules/oms/orders/search/OrderListPage.vue',[ 'OrderDetailDrawer', '@drill-down-requested="openDetail"', '@row-double-clicked="openDetail"', 'orderApi.getDetail', 'exportCsv', ]) if(orderList.includes('@row-double-clicked="row=>router.push'))failures.push('OMS-ORD-001 still destroys list context on double click') const orderDefinition=read('apps/web/src/modules/oms/orders/search/order-list.definition.ts') if(orderDefinition.includes("id: 'hold'"))failures.push('OMS-ORD-001 exposes Hold command without an implemented domain operation') requireTokens('apps/web/src/modules/erp/items/ItemMasterPage.vue',[ 'pendingTransition', 'KbxUnsavedChangesDialog', 'selectRowByKey', 'saveThenTransition', '@selection-changed="requestChoose"', ]) requireTokens('apps/web/src/modules/oms/orders/register/OrderRegisterPage.vue',[ 'pendingReset', 'KbxUnsavedChangesDialog', 'focusNextEditableCell', 'copyCurrent', 'ref="detailGrid"', ]) const registration=read('apps/web/src/modules/oms/orders/register/useOrderRegistration.ts') for(const token of ['return false','return true','function copyCurrent'])if(!registration.includes(token))failures.push(`useOrderRegistration missing ${token}`) for(const path of [ 'apps/web/src/modules/oms/orders/search/useOrderSearch.ts', 'apps/web/src/modules/oms/orders/register/OrderRegisterPage.vue', 'apps/web/src/modules/erp/items/ItemMasterPage.vue', ]){ if(read(path).includes('Promise.resolve()'))failures.push(`${path} contains a visible-command no-op Promise.resolve()`) } if(failures.length){ console.error('Golden FE parity v41 validation failed:\n- '+failures.join('\n- ')) process.exit(1) } console.log('Golden FE parity v41 PASS: controlled AG Grid selection, detail Drawer context, Lookup focus continuation, and dirty intra-screen transitions.')