import fs from 'node:fs' const read = (file) => fs.readFileSync(file, 'utf8') const expect = (condition, message) => { if (!condition) { console.error(`FAIL: ${message}`) process.exit(1) } console.log(`PASS: ${message}`) } const home = read('packages/kbx-ui/src/shell/KbxHomePage.vue') expect(home.includes('moduleSummaries'), 'home derives module-level navigation summary from allowed navigation entries') expect(home.includes('kbx-home__module-rail'), 'home exposes an explicit module work launcher rail') expect(home.includes('selectModule(module:string)'), 'home module launcher uses one controlled navigation path') expect(home.includes('id="kbx-home-explorer"'), 'home work explorer has a stable focus/scroll target') expect(home.includes('전체 업무 보기'), 'filtered home can return to the full work explorer without hidden navigation') expect(home.includes('favoriteCount') && home.includes('openCount'), 'home module rail exposes favorite/open work context instead of decorative cards') const master = read('packages/kbx-ui/src/components/KbxMasterPage.vue') expect(master.includes("import KbxSectionHeader"), 'T02 master template uses the standard section heading component') expect(master.includes('listTitle?:string') && master.includes('detailTitle?:string'), 'T02 exposes list/detail anatomy without custom page markup') expect(master.includes('kbx-master-page__list-body') && master.includes('kbx-master-page__detail-body'), 'T02 separates pane heading from pane work body') const transaction = read('packages/kbx-ui/src/components/KbxTransactionPage.vue') expect(transaction.includes('headerTitle?:string') && transaction.includes('detailTitle?:string'), 'T03 exposes explicit header/detail work anatomy') expect(transaction.includes('detailCount?:number'), 'T03 exposes detail row context in the template contract') expect(transaction.includes('kbx-transaction-page__header-body') && transaction.includes('kbx-transaction-page__detail-body'), 'T03 preserves distinct transaction work surfaces') const queue = read('packages/kbx-ui/src/components/KbxQueuePage.vue') expect(queue.includes('queueTitle?:string') && queue.includes('queueCount?:number'), 'T06 queue template exposes actionable queue anatomy') expect(queue.includes('kbx-queue-page__content-body'), 'T06 separates queue heading from queue result state') const reconcile = read('packages/kbx-ui/src/components/KbxReconcilePage.vue') expect(reconcile.includes('comparisonTitle?:string') && reconcile.includes('comparisonCount?:number'), 'T07 reconcile template exposes comparison anatomy and result count') expect(reconcile.includes('kbx-reconcile-content__body'), 'T07 separates mismatch context from comparison work body') const goldenOrder = read('apps/web/src/modules/oms/orders/register/OrderRegisterPage.vue') const goldenItem = read('apps/web/src/modules/erp/items/ItemMasterPage.vue') const queuePage = read('apps/web/src/modules/wms/work/WmsWorkPage.vue') const reconcilePage = read('apps/web/src/modules/common/reconcile/ReconcilePage.vue') expect(goldenOrder.includes('header-title="주문 정보"') && goldenOrder.includes('detail-title="주문 상품"'), 'OMS order transaction applies the T03 anatomy contract') expect(goldenItem.includes('list-title="품목 목록"') && goldenItem.includes('detail-title="품목 상세"'), 'ERP item master applies the T02 anatomy contract') expect(queuePage.includes('queue-title="현재 작업 Queue"'), 'WMS work page names its actionable queue surface') expect(reconcilePage.includes('comparison-title="OMS ↔ WMS 대사"'), 'reconcile page names its comparison surface') const referenceHtml = read('apps/web/fe-reference/index.html') const referenceJs = read('apps/web/fe-reference/kbx-fe.js') const referenceCss = read('apps/web/fe-reference/kbx-fe.css') expect(/FE Reference Lab v5[2-9]/.test(referenceHtml), 'static HTML reference preserves the v52+ FE operational navigation build contract') expect(referenceHtml.includes("connect-src 'self'"), 'static HTML reference CSP restricts network connections to same origin') expect(referenceHtml.includes("frame-src 'none'") && referenceHtml.includes("worker-src 'none'"), 'static HTML reference explicitly closes unused frame/worker execution surfaces') expect(referenceJs.includes('class="home-module-rail"'), 'static JavaScript reference mirrors the module work launcher rail') expect(referenceJs.includes('data-home-module="ALL"'), 'static JavaScript reference offers an explicit all-work reset target') expect(referenceJs.includes("scrollIntoView({block:'start',behavior:'smooth'})"), 'static module navigation lands on the work explorer instead of silently filtering') expect(referenceCss.includes('.home-module-rail'), 'static reference has dedicated module launcher presentation') expect(referenceCss.includes('.home-module-rail button[aria-pressed="true"]'), 'module launcher exposes its active state accessibly') expect(referenceCss.includes('@media(forced-colors:active){.home-module-rail'), 'module launcher retains an active cue in forced-colors mode') console.log('PASS: FE operational navigation and screen anatomy v52 contract')