# KBX FE Authoritative Outcome & Runtime Evidence Hardening v57

## 1. 냉정한 진단

v56까지 KBX의 공통 Template, Overlay Focus, Excel 6단계, Home Triage, WMS retry/idempotency 계약은 문서와 정적 회귀 기준에서 상당히 성숙했다. 그러나 현장 QA 관점에서는 두 종류의 위험이 남아 있었다.

첫째, **Transport Success와 Business Success가 혼재**했다. HTTP 200이어도 Backend가 `ResolvedCount=0, RejectedCount=1` 또는 `CreatedOrUpdatedCount=0, SkippedCount=1`을 반환할 수 있는데 일부 FE가 응답 body를 버리거나 성공 Telemetry를 기록할 수 있었다. 업무시스템에서 이는 "통신 성공"을 "업무 성공"으로 오해하는 전형적인 운영 사실성 결함이다.

둘째, **테스트 코드 존재와 실행 가능한 테스트 체계가 혼재**했다. Playwright spec은 많았지만 root에 `@playwright/test`, baseURL, webServer, viewport project가 없었다. 상대 URL을 쓰는 E2E가 실제 CI에서 어떻게 실행되는지가 계약화되지 않았다. `packageManager: pnpm@10` 역시 Corepack이 요구하는 정확한 semver가 아니었다.

v57은 새 추상화를 추가하는 대신 이 두 종류의 "마지막 10%"를 닫는다.

## 2. T06 — Authoritative Operations Outcome

### 문제

`ClaimWorkItemsResponse`는 이미 `claimedCount/skippedCount`를 제공했지만 Resolve 결과도 동일한 수준으로 사용자에게 남아야 한다. 기존 구조에서는 resolve HTTP 200 후 실제 `rejectedCount`가 있어도 Drawer가 닫히고 성공 Telemetry가 남을 수 있었다.

### 변경

- `ResolveWorkItemsResponse(resolvedCount, rejectedCount)`를 실제 Page가 소비
- Claim/Resolve를 하나의 `actionReceipt`로 통합
- 요청/성공/건너뜀 또는 거절 건수를 persistent inline receipt로 표시
- partial result이면 `최신 상태 조회`를 명시
- 결과 Receipt로 Focus 이동
- `exception.resolved` Telemetry는 `resolvedCount > 0`인 경우에만 기록

즉 HTTP status는 transport outcome이고, 업무 성공 여부는 response body의 authoritative count가 결정한다.

## 3. T07 — Reconcile Outcome & Recovery

### 문제

Backend의 Create Exceptions 응답은 `CreatedOrUpdatedCount/SkippedCount`를 반환한다. FE가 이를 `unknown`으로 버리면 실행시점에 이미 정상/해결 상태로 바뀐 Row를 사용자가 "등록 성공"으로 오해할 수 있다.

### 변경

- `CreateReconcileExceptionsResponse`를 명시적 Type으로 승격
- 요청/생성·갱신/건너뜀 count 표시
- partial이면 Receipt Focus + `최신 대사 조회`
- 생성된 항목이 있으면 `예외 센터 보기`
- 원천 OMS/WMS 값은 Reconcile 화면에서 수정하지 않음

Reconcile은 데이터 수정화면이 아니라 Evidence → Exception Workflow 전환 화면으로 유지한다.

## 4. T09 — Shared PDA Scope-Race Hardening

### 문제

v56에서 retry queue 자체는 tenant/user scope별로 분리했지만, Scan request가 진행 중인 순간 사용자가 교체되면 callback 시점의 "현재 scope"와 command 발행 시점 scope가 달라질 수 있었다.

이 상황에서 response-loss command가 새 사용자의 queue에 들어가거나 이전 작업의 server confirmation이 새 사용자 화면에 나타나는 것은 공용 PDA에서 심각한 교대근무 경계 침범이다.

### 변경

- `ScopedScanMutation { command, scope }`
- Scan 발행 시 scope snapshot
- success/error 모두 captured scope로 retry item 제거/등록
- callback 시 현재 scope와 다르면 현재 UI/task/lastConfirmedScan을 변경하지 않음
- retry flush 전체 loop도 시작 scope에 pin
- scope change 시 task telemetry abandon, last confirmed scan/overlay context reset

Idempotency는 중복 실행 방지이고, scope isolation은 사용자/tenant 경계 보호다. 둘을 별개로 유지한다.

## 5. Demo API — Runtime Contract Repair

정적 검증이 통과해도 Demo API가 실제 DTO와 다르면 Browser E2E는 제품 코드를 검증하지 못한다.

v57은 Operations demo data를 `sourceModule/sourceType/sourceId/referenceNo/sourceScreenId/code/severity/status/owner/ageMinutes/actions` 계약으로, Reconcile data를 `expectedValue/actualValue/differenceValue/reason/status/summary` 계약으로 정렬했다.

Demo Resolve도 authoritative state 변경 시 version을 증가시키고, Reconcile Create Exceptions는 `createdOrUpdatedCount/skippedCount`를 반환한다.

Demo는 별도 제품이 아니라 실제 FE 계약을 재현하는 실행 fixture여야 한다.

## 6. Browser QA Runner 계약

새 `playwright.config.ts`는 다음을 고정한다.

- 기본 Demo URL: `http://127.0.0.1:4173`
- 외부 `KBX_E2E_BASE_URL`이 없으면 `pnpm dev:web:demo` 자동 기동
- Desktop Chromium: 1440×900
- WMS Mobile Chromium: 390×844
- trace: retain-on-failure
- screenshot: only-on-failure
- video: retain-on-failure

Root scripts는 `test:unit`, `test:e2e`, `test:e2e:desktop`, `test:e2e:wms`, `test:fe`를 제공한다.

추가 E2E는 다음 운영 사고를 직접 모델링한다.

1. Operations HTTP 200 + `rejectedCount=1` → 성공으로 가장하지 않음
2. Reconcile HTTP 200 + `skippedCount=1` → partial receipt 및 복구
3. WMS 첫 Scan response loss → 동일 idempotency key로 1회 안전 재전송 → server confirmed truth 이후에만 최근 확인 갱신

## 7. CI/Release Gate

`.gitea/workflows/kbx-quality-gate.yaml`은 lockfile 존재 시:

`install → typecheck → unit → demo build → Chromium install → Playwright E2E`

를 실행한다.

Release Readiness는 lockfile이 없으면 runtime evidence를 BLOCKED로 기록하고 실패한다. 운영 배포 후보가 "정적 계약 PASS"만으로 runtime 검증을 통과한 것처럼 승격되지 않게 한다.

## 8. 현재 검증 결과

`node scripts/validate-kbx.mjs` 전체 PASS.

- 161 tokens
- 20 screens
- 86 components
- 34 core APIs
- 310 TypeScript/Vue script units
- T01~T09 9/9
- Design Debt 116 <= 131
- Design-Code Parity PASS
- Release Governance major PASS

## 9. Runtime 제한

현재 artifact 환경은 npm registry DNS lookup이 `EAI_AGAIN`으로 실패한다. 정확한 `pnpm@10.33.4`를 Corepack이 내려받지 못하므로 lockfile 생성/의존성 설치/Playwright browser runtime 실행을 완료하지 못했다.

따라서 다음은 **PASS라고 주장하지 않는다**.

- `pnpm install --frozen-lockfile`
- Vue production typecheck/build
- Vitest runtime suite
- Playwright Desktop/WMS E2E

실행계약은 구성했지만 Runtime Evidence는 환경이 준비된 CI/개발 머신에서 반드시 생성해야 한다.

## 10. 다음 P0

1. Registry 접근 가능한 환경에서 `pnpm-lock.yaml` 생성 및 고정
2. Desktop 1440×900 Golden Screen runtime suite 실행
3. WMS 390×844 response-loss / offline / operator-scope-switch 시나리오 실행
4. Playwright trace/screenshot/video를 Release Evidence로 보존
5. Browser PASS 이후에만 "현장 사용 PASS" 상태로 승격

다음 단계에서도 새로운 UI Framework보다는 이 Runtime Evidence와 실제 업무 완료율을 우선한다.
