# Progress Current

## Status

| 항목 | 현재 값 |
|---|---|
| Status | Active current-truth dashboard |
| Owner | APP/기술 기준: 주우철 · Web/PC/backend/관측성: 정정일 |
| Last verified | 2026-07-18 KST |
| Verified baseline | #974~#979 기능 slice, #980 runtime boundary guard, #981 source-bound lifecycle 회귀, #982 read-only Android native preflight와 #1012 secure driver proof가 local Spring·PostgreSQL·Floci·Android·unit/static evidence를 확보함; delivery state는 각 GitHub issue가 소유 |
| 범위 | 역할별 APP/backend 연결, provider, realtime/push, APP release readiness, 문서 도달성 |

이 문서는 현재 상태와 다음 판단만 유지한다. PR별 진행 기록은 [2026-07 archive](./archive/2026-07.md), 7월 10일 기준선은 [2026-07-10 milestone](./milestones/2026-07-10.md)에서 확인한다.

## Canonical Sources

- 문서 계층과 현재 기술 결정: [Docs Index](../README.md)
- 역할과 화면/API 권한: [RBAC Matrix](../10-product/RBAC_MATRIX.md)
- APP/backend endpoint와 envelope: [API Contract](../20-contracts/API_CONTRACT.md)
- file/OCR/document/external handoff shape: [Provider Adapter Contract](../20-contracts/PROVIDER_ADAPTER_CONTRACT.md)
- foreground realtime과 OS push 경계: [Realtime Push Contract](../20-contracts/REALTIME_PUSH_CONTRACT.md)
- APP provider 상태와 halt 조건: [Provider Policy](../40-mobile/policies/PROVIDER_POLICY.md)
- APP build, OTA, store 기준: [Release Strategy](../40-mobile/RELEASE_STRATEGY.md)
- APP 검수 정본: [Test Coverage Graph](../../apps/mobile/e2e/TEST_COVERAGE_GRAPH.md)
- generated review source: [Mobile UX Index](../80-artifacts/ux-flow/mobile-index.json)

이 문서는 위 계약의 상세 ownership을 복제하거나 변경하지 않는다. 상태값, endpoint, provider shape, 권한이 달라지면 해당 정본을 먼저 갱신한다.

## Documentation State

- portal 대상 문서는 `AGENTS.md`, `CLAUDE.md`, root README, Docs Portal에서 모두 도달 가능하다.
- `.claude/commands/**`와 `.specify/templates/**`는 도구가 직접 여는 독립 진입점이며 서비스 정본이 아니다.
- 핵심 문서는 Pandoc HTML/AST smoke를 통과했고 local Markdown target은 `docs:check`로 검증됐다.
- historical source는 현재 결정을 소유하지 않으며, 해석 충돌은 [문서 충돌 등록부](../00-governance/DOCUMENT_CONFLICT_REGISTER.md)에서만 승격한다.

## Current Foundation

- Backend는 Kotlin Spring, PostgreSQL 17, JPA, Flyway 기반이다.
- 인증은 자체 JWT와 `roles` claim이 현재 구현 기준이며, APP은 bearer token과 SecureStore 경계를 사용한다.
- APP은 Expo SDK 56 단일 앱이고 onboarding/login 이후 보유 role context를 선택한다.
- credential-free HTTPS `EXPO_PUBLIC_API_BASE`와 exact Android emulator HTTP origin `http://10.0.2.2:8080`만 운전자 runtime client를 Spring backend mode로 올린다. query/hash marker, credential, malformed raw syntax, external HTTP, 누락 값은 mock 검수 경로를 유지한다. 운전자 직접 role route는 wrapper가 명시적으로 mock runtime을 주입하며, 인증 진입만으로 API base가 없는데 backend mode로 승격하지 않는다.
- 역할은 `emitter`, `dispatcher`, `driver`, `processor`로 분리한다.
- 운전자는 lifecycle notification 대상이지만 현재 APP chat room viewer는 아니다.

## Role-Based APP / Backend State

| 역할 | 현재 APP/backend 연결 | 남은 경계 |
|---|---|---|
| 배출자 | login/session, 배출 신청, history/detail, 취소 conflict, 알림, chat, local/dev 문서 capability | production 문서/media provider, Olbaro 실연동 |
| 배차담당자 | login/session, pending board read, 배차 assign/confirm, unlinked pending request 취소, 알림, common chat | assigned-row 취소/재배차 canonical id 계약, 외부 지도/전화 실행 |
| 운전자 | active assignment queue, confirm, 업무 시작 전 차량 후보/변경, 상차·하차 secure upload session과 stable `fileId` proof, 상·하차 사진 Android camera-only capture와 surface-specific app-private artifact, 하차 owner-scoped draft 복구, 상차 안전 서명 local canvas와 app-private PNG 경계, 계근표 Android camera-only app-private JPEG와 upload/OCR/weighing·durable queue handoff, 차량 정비/주유 기록, `expo-sqlite` durable proof queue, backend proof submitter, app-start/foreground recovery composition | `needs_review` 수동 보정, network recovery listener, process-death/replay/conflict device evidence, physical-device/OEM evidence, production credential/OCR, 외부 지도/전화; delivery state는 GitHub #973 |
| 처리자 | 입고 board/detail, approve, weighing, treatment result, actionability, common chat | production upload/OCR, Olbaro 제출 경계 |

### 공통 APP 상태

- `/login`, session restore/logout, 보유 role 조회와 active role 선택용 API adapter가 backend mode에 연결돼 있다. 그러나 `entry=login&role=driver` recovery는 현재 `login-entry` 인증 상태와 ready backend today board만 확인하며, #1049 shared auth/runtime API-base allowlist와 active driver role의 `/session/me?role=driver` 검증은 production gate로 남아 있다.
- 배출자·배차담당자·처리자의 기존 More 화면은 active role의 `companyName`, 사용자 이름, 역할을 표시하고 APP bearer logout 뒤 `/login`으로 route를 교체한다. Android Back으로 보호 화면에 재진입하지 않는다.
- role 직접 진입은 화면 검수용 mock 경로이며 production auth를 대신하지 않는다. pending camera-result recovery는 `login-entry` 인증 상태의 운전자가 schedule/unloading proof surface를 실제로 열고 backend today board가 ready일 때만 local owner scope로 시도하며, `mock-direct` fallback, APP-root/role-route auto-open, active driver notification/deep-link target 선점은 하지 않는다. authenticated `login-entry` draft는 app-private persisted storage를 사용하지만 recovery gate 뒤에만 다시 연다. `e2c41743` 이후 `mock-direct` draft는 capture instance-local 메모리만 사용하는 non-durable 상태라서 나중의 새 `mock-direct` session은 이전 session의 camera artifact를 restore/view할 수 없다. 이는 active driver role의 `/session/me?role=driver` 검증이 아니며, #1049의 두 distinct P0 gate인 shared auth/runtime API-base allowlist와 active-role verification이 production gate로 남아 있다. strict driver runtime base enforcement는 system-wide가 아닌 driver 전용 경계다.
- APP 주요 domain spine은 배출 신청에서 배차, 운전자 증빙, 처리자 승인/실적까지 local backend로 검증돼 있다.
- 운전자 backend mode는 상차 사진 2장·서명 1건과 하차 사진 2장을 private upload session으로 저장한 뒤 stable `fileId`만 lifecycle action에 전달한다. Backend는 canonical 9개 안전 체크리스트, 운반일, 배정 운전자·handover·surface·uploaded state를 같은 transaction에서 검증하고 immutable object key를 `Photo`와 `SafetyChecklist`에 연결한다. APP은 중복 제출을 합치고 부분 성공 file을 foreground retry에서 재사용하며, 미청구 uploaded proof는 24시간 orphan cleanup으로 수렴한다. #1018에서 retryable proof action을 owner-scoped SQLite metadata와 app-private file로 durable queue에 저장하고, 실제 파일 크기 기반 quota preflight·SQLite atomic enqueue·legacy row 격리·schema rebuild transaction·DB manifest와 app-private file의 orphan reconciliation·backend proof submitter와 app-start/foreground recovery composition을 연결했다. 2026-07-16에 하차 사진 2장 surface를 Android camera-only `expo-image-picker` -> JPEG re-encode -> app-private file/stable `captureId` 경계와 owner-scoped saved draft 복구에 연결했다. 2026-07-18에는 상차 사진도 별도 `loading-{assignmentId}-photo-{slot}` namespace의 같은 camera-only 경계로 연결했다. 상차는 정확히 두 개의 distinct `camera` provenance `file://` artifact와 실제 서명이 있어야 CTA가 활성화되고, incomplete/fixture/mock/duplicate URI를 거부한다. 상차 draft는 session-local이라 close/backdrop/pan/unmount에서 정리하며 relaunch recovery를 주장하지 않는다. 실패한 submit은 사진을 유지하고, direct adapter가 소비했거나 durable queue가 copy를 소유한 성공 뒤 source를 정리한다. 하차 request의 두 artifact slot에는 정확히 두 `photoOrigins`가 필수이며 출처 누락을 camera로 보정하지 않는다. unloading `origin=fixture`는 운영 upload file/network I/O 전에 거부된다. 상차 서명은 실제 canvas 입력을 PNG magic bytes/크기로 검증해 app-private file URI로 넘긴다. Driver 계근표는 system camera -> JPEG re-encode -> exact `Paths.document/driver-proof-capture/weighing-{assignmentIdLength}-{assignmentId}-photo-1-{captureId}.jpg`에 저장하고 기존 upload/OCR/weighing 또는 durable queue copy로 handoff한다. Backend UUID를 포함해 파일명에 그대로 보존할 수 있는 assignment ID는 `[A-Za-z0-9_-]{1,64}`로 허용하고 그 밖의 값은 손실 치환·truncate하지 않고 fail closed 한다. Length prefix로 delimiter alias를 제거한다. UI, direct backend entry, queue enqueue가 같은 validator를 사용해 assignment mismatch, lookalike/unmanaged root, non-JPEG, query/hash/NUL, raw/encoded traversal을 file/network I/O 전에 거부한다. Queue replay는 capture root가 아니라 exact app-private `driver-proof-queue` immediate-root JPEG만 별도 trusted boundary로 허용하며 replay source 검증을 file existence/today board/owner/submit보다 먼저 수행한다. Network recovery listener와 process-death/replay/conflict 실제 기기 evidence는 별도 gate다.
- 상차와 계근 source artifact는 role-shell startup에서 capture root의 `loading-*.jpg`, `weighing-*.jpg` namespace만 각각 process-wide 1회 sweep하며 하차 draft, signature, queue copy namespace를 건드리지 않는다. 같은 process의 후속 manager는 완료·진행 중 promise를 재사용하고 실패한 sweep만 재시도한다. Sweep 완료 전에 새 capture를 열지 않는다. Submit 중 unmount는 source를 handoff가 끝날 때까지 보존하고, 실패가 mounted surface에서 끝나면 retry를 위해 유지하되 unmount 뒤 실패가 확정되면 정리한다. Direct consume 또는 durable copy 성공 뒤 첫 source cleanup이 실패하면 domain action을 재전송하지 않고 close/unmount에서 idempotent cleanup만 재시도한다. `origin=camera`는 standard-client camera flow invariant이며 server challenge/device attestation이 없는 현재 wire에서 보안 등급의 provenance를 증명하지 않는다.
- #1032 Cycle 1의 하차 입력 경계는 `camera capture -> JPEG re-encode -> app-private draft`이며, 앱 재시작은 하차 surface를 자동 route하지 않는다. authenticated `login-entry` draft는 수동 re-entry, ready board, actionability gate 뒤에만 복구한다. `camera | fixture` provenance는 saved draft와 durable queue까지 보존되고, unloading `origin=fixture`는 운영 upload file/network I/O 전에 거부된다.
- `driver-unloading-camera-denied`는 guarded backend subflow와 별개의 `mock-direct` permission-edge flow다. 정확한 단일 DEV-only app-link `driverAssignmentFixture=driver-z5488156120-loading-started`가 알려진 mock assignment 상태만 투영하며 사진 artifact를 만들지 않고 backend mode/production에는 적용되지 않는다. 2026-07-18 source-bound flow는 loading checklist 없이 `driver.unloading-proof.screen`에 진입해 permission deny -> 사용자 안내 -> 0/2 -> disabled 완료를 통과했다. canonical receipt와 final screenshot은 `artifacts/mobile/maestro/driver-unloading-camera-denied/`에 있고 final staged diff fingerprint를 기록한다.
- 상차 안전 서명은 local-only WebView canvas에서 생성한 PNG를 검증해 app-private `file://` artifact로 저장하고, raw data URL 대신 기존 loading proof request/queue 경계에 전달한다. `2026-07-18` Android emulator에서 `driver-loading-checklist-visual`의 실제 swipe -> ready -> clear -> empty와 `driver-dispatch-schedule`의 상차 입력 진입을 source-bound receipt로 확인했다. 정본 evidence는 `artifacts/mobile/maestro/driver-loading-checklist-visual/latest.json`과 `artifacts/mobile/maestro/driver-dispatch-schedule/latest.json`이며, 법적 전자서명과 physical-device/OEM 완료 주장은 별도 gate다.
- 상차 사진 surface는 Figma note `893:2757`의 "서명 뒤 사진 2장, 이후 상차 시작" 계약을 따르는 derived-actual UI다. 정확한 photo frame이 없으므로 pixel parity는 주장하지 않는다. `driver-loading-photo-camera`는 Android system camera의 `Shutter`/`Done`을 통해 실제 2장을 받아 두 artifact testID와 enabled submit을 확인하고 상차 시작까지 완료했다. `driver-loading-photo-camera-denied`는 권한 거부 안내와 disabled submit을 확인했다. canonical `latest.json` 두 건은 `status=ok`와 final staged diff fingerprint를 함께 기록한다.
- Driver 계근 surface는 Figma note `1011:2112`를 근거로 한 derived-actual UI이며 pixel parity를 주장하지 않는다. Android emulator의 `driver-weighing-ticket-camera` positive/denied source-bound receipt는 모두 `status=ok`다. Positive는 OCR 등록과 실중량 `7,000kg` 완료를, denied는 명시적 권한 안내·`0/1`·disabled CTA를 확인했다. #1049 shared auth/runtime API-base allowlist와 active driver role `/session/me?role=driver` verification, `needs_review` 수동 보정, network recovery, process-death/replay/conflict, physical-device/OEM evidence와 production provider/Google Cloud Vision은 별도 gate다.
- backend mode의 emitter create, dispatcher assign, driver confirm, processor approve, chat read/send 대표 mutation은 중앙 guard가 실제 runtime client request sequence와 각 local mock store의 전후 snapshot을 비교한다. unauthorized/conflict/retryable 실패는 backend request로만 귀결되고 mock state를 변경하지 않는다. 나머지 mutation 경계는 각 runtime client의 method-specific 테스트가 소유한다.
- chat list/detail/read/send는 backend alias를 사용하고 attachment persistence/linking을 지원한다. 실패한 첨부는 같은 APP session에서 동일 draft로 재시도하며, 같은 room의 중복 send는 client-side gate와 backend `clientMessageId` 멱등 경계로 한 번만 저장한다. 만료되거나 열기에 실패한 read capability는 room refresh로 갱신한다.
- in-app lifecycle notification CTA는 `MobileNotificationTarget` typed target을 emitter/dispatcher/driver/processor의 기존 detail surface로 연결하고, header Back/Android Back → 같은 notification detail → notification list 복원 경로를 고정한다. terminal lifecycle 이후 active board에서 빠진 dispatcher/driver 항목은 mock mode deep-link snapshot으로만 복원하며 backend mode에는 mock fallback을 사용하지 않는다. `lifecycle-chat-notification-proof` Android Maestro가 2026-07-13 통과했다.
- provider가 준비되지 않은 action은 성공처럼 보이지 않고 pending, disabled reason, retry 상태로 닫는다.

## Provider State

| 영역 | 현재 상태 | Production gap |
|---|---|---|
| Upload | local/S3-compatible private-object adapter, source ETag conditional finalize, final rehash, MIME/size 검증, stale verifying·terminal session의 48시간 idempotent cleanup이 존재. Chat/driver proof/driver·processor weighing adapter가 secure session과 stable `fileId` 경계를 사용한다. Driver proof session은 handover lock 아래 배정 운전자와 surface별 2-package quota를 확인하고, 미청구 파일은 24시간 뒤 provider delete까지 재시도한다. 인계 상세는 영구 object key 대신 참여 회사 RBAC를 확인한 10분 read capability만 반환하며 legacy 사진은 안전한 file metadata가 없으면 URL을 생략한다. G013에서 durable queue의 owner scope, app-start/foreground recovery, SQLite 재오픈, cleanup_pending 정리 경계를 추가했다. 상·하차 사진 2장과 driver 계근표 1장은 Android camera-only app-private JPEG로 연결했고 하차만 saved draft recovery를 제공한다. 계근 source는 managed namespace만 backend/queue에 전달하고 direct consume 또는 durable copy 뒤 정리한다. 상차 안전 서명은 local canvas PNG를 검증한 app-private file URI만 proof 경계로 전달한다. | network recovery listener, process-death/replay/conflict 및 physical-device/OEM evidence, production bucket/credential, public access block, `staging/` lifecycle policy와 provider smoke, malware scan |
| OCR | local fake OCR, Google Cloud Vision smoke, backend `OcrAcceptancePolicy`가 존재. 필수 field·gross/tare 관계·required confidence `0.90` 미만을 `needs_review`로 분류하는 경계를 테스트로 고정 | production credential/adapter, 대표 benchmark, 실제 provider 품질 evidence |
| Document/media read | 10분 read capability, owner/참여 company RBAC, soft-delete request/approval, legal hold, retention purge가 backend에 존재 | production provider smoke, 운영 승인 wiring, 회사 종료 export, thumbnail/cache |
| Phone/map/support | shared runtime value helper와 네이버지도 URL allowlist가 존재 | 실제 opener, runtime source, audit policy |
| Location | explicit driver action의 foreground event-time evidence만 허용 | background/continuous tracking은 별도 product decision |
| Olbaro | backend 계약과 local lifecycle 경계가 존재 | 테스트 계정, HALF MODE 실측, 운영 credential |

- local/dev provider proof는 production provider readiness를 의미하지 않는다.
- raw URL, object key, credential, OCR 원문은 APP 컴포넌트와 evidence log에 노출하지 않는다.
- 상세 adapter shape와 provider state 승격 조건은 canonical provider 문서를 따른다.

## Realtime / Push State

- APP root layout이 `bootstrapAppChatRealtime`를 호출한다.
- local/dev backend mode는 API base를 websocket `/ws`로 변환해 STOMP foreground transport를 주입한다.
- connection 직전에 SecureStore access token을 읽고 bearer `CONNECT` header를 구성한다.
- config가 없거나 유효하지 않으면 explicit no-op transport와 REST refresh fallback으로 수렴한다.
- Web/backend의 shared realtime event schema를 재사용하며 screen에서 raw STOMP client를 만들지 않는다.
- Expo Push가 OS push의 primary provider다.
- APP permission 상태 UI와 Expo token registration payload skeleton은 구현돼 있다.
- local/dev push device registration/storage는 #1023에서 `PUT|DELETE /mobile/push/device-registrations`와 `notification:register` RBAC로 구현·검증됐다.
- Expo delivery/receipt/retry, production credential, APP 자동 registration lifecycle, notification tap role/session 복원은 open이다.
- production broker topology, replay/idempotency, latency/SLA도 open이다.

## Release State

- EAS project는 `@bootalk/zerro`, Android package는 `com.bootalk_appdev.zerro`다.
- Android development/releases/production build profile이 존재한다.
- `releases`는 internal verification lane이며 production 배포가 아니다.
- 2026-07-14 기준 mobile static gate, Expo install compatibility, Expo Doctor `21/21`, clean Android prebuild/debug APK build, dev-client install/launch와 mock-mode login/role smoke가 통과했다.
- 2026-07-20 `origin/develop` `64a3d7d1` 기준 Android development client cloud build [`50bd5924-2ebd-40bb-bffa-dbe1fa384e37`](https://expo.dev/accounts/bootalk/projects/zerro/builds/50bd5924-2ebd-40bb-bffa-dbe1fa384e37)가 `FINISHED`다. profile/channel/EAS env는 모두 `development`, runtimeVersion은 `1.0.0`, artifact는 internal APK다.
- 같은 SHA와 runtimeVersion의 Android OTA update [`dba9385f-7e39-46ad-bc77-edbb0a200b4c`](https://u.expo.dev/update/019f7edf-70ca-72c2-876d-1eff62f82d29)를 `development` channel/branch에 게시했다. EAS development environment에는 `EXPO_PUBLIC_APP_ENV=development`만 있고 `EXPO_PUBLIC_API_BASE`는 없으므로 backend mode는 mock이다.
- development client는 Update URL/QR 또는 launcher Extensions로 compatible update를 명시적으로 여는 공유 QA lane이다. 자동 channel 적용이 필요한 stakeholder APK와 production OTA/store submit은 여전히 비활성이다.
- cloud APK는 LG V30(`LGM-V300L`, Android 9)에 `adb install --no-streaming -r`로 설치했고 development launcher 실행, group-specific OTA deep link, `runtimeVersion 1.0.0`, mock 역할 선택 surface와 crash-free foreground를 확인했다. production signing/credential write, store submit, iOS build는 수행하지 않았다.
- native dependency/config 변경은 static gate만으로 닫지 않고 prebuild/build evidence를 요구한다.

## Open Work

- 미구현 기능의 전체 순위와 완료 조건은 [Mobile Release Strategy의 Production Function Closure Priority](../40-mobile/RELEASE_STRATEGY.md#production-function-closure-priority)가 소유한다.
- 구현 issue 발행 가능 여부와 선결 질문은 [Decision Gates](../40-mobile/RELEASE_STRATEGY.md#decision-gates-before-implementation-issues)가 소유한다. local 원천 audit에서 확인된 historical proposal은 gate 없이 backlog로 승격하지 않는다.
- P0: #1049 shared auth/runtime API-base allowlist와 active driver role `/session/me?role=driver` verification, production media credential/smoke, 문서 최종 서식·글꼴/production storage, Android 문서 저장·만료 실기기 evidence, durable queue의 network recovery·process-death/replay/conflict 실기기 evidence, Google Vision production adapter/benchmark. 상·하차 사진과 driver 계근표 camera input은 Android camera-only app-private JPEG에 연결됐다. Loading positive/denial, unloading denial과 driver weighing positive/denied source-bound Android emulator receipt는 모두 완료됐고 physical-device/OEM evidence는 남아 있다. 하차 saved draft는 `login-entry` 운전자의 수동 재진입·ready board·actionability gate 뒤에만 복구하며 loading/weighing draft는 session-local이다. OCR acceptance threshold와 `needs_review` 분류는 backend policy와 테스트로 닫혔지만 APP 수동 보정과 실제 provider 품질은 아직 주장하지 않는다. APP 문서 viewer는 capability 만료·저장 권한 재요청·Android SAF 저장 adapter·공유 거부 UX까지 닫혔고 production 권한 enforcement와 실제 기기 저장 결과가 남아 있다.
- P1: Expo Push delivery/tap, production realtime, external handoff, APP 계정 lifecycle·세부 RBAC, Olbaro 실계정 검증. #1023 local/dev registration/storage slice 이후 delivery/receipt/retry를 별도 승격한다.
- R0 병렬 gate: Android RC/store/signing/release observability. production submit은 P0와 승인 gate가 닫히기 전 실행하지 않는다.
- 결정 없이 진행 가능한 APP closure는 root issue #972의 #973~#982 순서로 관리했다. #974~#979 기능 slice와 #980 backend-mode mock mutation 중앙 guard, #981 source-bound Android 회귀, #982 read-only Android native preflight까지 닫았다. branch/PR/merge 전달 상태는 현재 문서에 복제하지 않고 각 GitHub issue가 소유한다.
- UX review source는 #973~#982의 goal-to-node/Figma anchor/flow/required evidence slot을 추적한다. local goal evidence manifest는 clean screenshot과 redaction-safe receipt의 source-set/hash/freshness를 검증하며, generated portal은 이를 최근 goal board로 보여준다.
- background location, direct FCM/APNs, native map SDK, iOS, OAuth/SMS/SSO는 현재 Android launch blocker가 아니며 scope 변경 시 재평가한다.

## Recommended Next Priority

1. #1012에서 운전자 상차·하차 lifecycle payload를 filename/local URI에서 secure upload session의 stable `fileId`로 승격하고 local Spring + Floci + Android flow로 검증했다.
2. `DG-DOC-01`의 versioned PDF renderer/private archive slice는 local Spring 및 S3-compatible adapter 경계까지 연결됐다. `intake_pending`/`treatment_recorded` 전이와 허용된 계근·처리 보정에서 append-only 정정본을 발급하며, source event·사유·참여 회사 snapshot·SHA-256·renderer version을 보존한다. #1026에서 Android SAF 저장 adapter, 저장 취소·실패 시 partial file 정리, 공유 disabled 상태를 APP에 연결하고 `emitter-history` Maestro를 재검증했다. 다음은 production storage credential, 최종 서식·한글 글꼴, transaction 이후 발급, Android 실제 저장·만료 evidence를 연결한다.
3. #1018에서 durable proof queue(`DG-OFFLINE-01`)의 owner-scoped SQLite metadata·app-private file·ordered drain, 실제 proof submitter와 app-start/foreground recovery composition을 연결했다. 2026-07-16에는 하차 사진 2장을 Android camera-only capture로 받아 JPEG re-encode app-private draft와 stable `captureId`로 복구하는 입력 경계를 추가했고, `camera | fixture` provenance를 queue까지 보존해 fixture를 operational upload/read/session/lifecycle mutation 전에 차단했다. 2026-07-18에는 loading 사진 2장과 driver 계근표 1장을 camera-only JPEG app-private artifact로 연결했다. Loading은 exact two/distinct/camera/file gate를, weighing은 exact assignment-bound capture root/filename과 trusted queue replay root를 사용한다. 두 surface 모두 session dismiss/replacement cleanup, mounted retry retention, direct/durable handoff success cleanup을 고정했고 성공 후 첫 cleanup 실패는 domain replay 없이 unmount cleanup으로만 재시도한다. 상차 서명은 실제 canvas 입력을 검증한 app-private PNG file URI로 연결했다. Driver weighing positive/denied source-bound Android emulator receipt는 완료됐다. 다음은 network recovery listener, process-death/replay/conflict 및 physical-device/OEM evidence를 증명하는 일이며, Google Vision production adapter/benchmark와 `needs_review` 수동 보정(`DG-OCR-01`)도 별도 VERIFY로 남아 있다. G014에서는 backend `OcrAcceptancePolicy`로 필수 field·confidence·weight relation의 `needs_review` 경계를 고정했다. logout/account switch의 sync/discard/cancel 선택은 별도 owner decision으로 유지한다. OS push tap role/session restore와 Expo delivery도 별도 pending으로 유지한다. #1023은 Google Sheet 수신자 matrix를 기준으로 local/dev Expo token 등록·폐기 저장과 `notification:register` 권한 경계를 추가해 구현·검증했다.

새 APP backend domain은 canonical screen/API gap이 확인될 때만 시작한다. 현재 APP 우선순위는 이미 연결된 domain spine 위의 provider/realtime/release closure다.

## Open Decisions

채택된 기술 상태는 [Decisions](../00-governance/DECISIONS.md), 구현 전 질문과 권장 기본값은 [Release Decision Gates](../40-mobile/RELEASE_STRATEGY.md#decision-gates-before-implementation-issues)가 소유한다. `DG-FILE-01` 정책과 backend core enforcement는 닫혔지만 production credential·운영 wiring은 VERIFY다. 현재 구현 우선 대상은 `DG-DOC-01`, `DG-OFFLINE-01`, `DG-OCR-01`이고, `DG-AUTH-01`, `DG-PUSH-01`, `DG-REALTIME-01`, `DG-HANDOFF-01`, `DG-OLBARO-01`, `DG-RELEASE-01`과 future background/continuous location은 별도 gate다.

## Known Issues

- 일부 requirements 문서는 역사적 원천 맥락을 포함하므로 현재 결정은 Docs Index와 constitution을 우선한다.
- Maestro와 agent-device 동시 실행은 Android `UiAutomation` 충돌을 만들 수 있어 같은 run에서 순차 실행한다.
- Android serial별 atomic lease가 live owner와 foreign owner를 보존하며, Maestro harness의 cleanup과 screenshot capture 전에 획득된다.
- sparse agent-device snapshot이 재발하면 APP 실패와 섞지 않고 별도 evidence 상태로 기록한다.
- fresh install 또는 Sentry 변경 뒤 stale Metro가 module resolve/LogBox 문제를 만들 수 있다.
- generated HTML은 검수 snapshot이며 Markdown/JSON 정본을 대신하지 않는다.

## Maintenance Rule

- 이 파일은 current truth, open work, next priority, open decisions, known issues만 유지한다.
- PR별 완료 기록과 긴 검증 로그를 이 파일에 누적하지 않는다.
- 새 snapshot history는 월별 archive 또는 milestone에 기록한다.
- role/API/provider/realtime/release 상세는 canonical docs에 기록하고 여기서는 링크와 현재 상태만 유지한다.
- 상태가 바뀌면 관련 canonical doc, APP coverage graph, mobile index JSON을 함께 점검한다.
- 매 compaction 때 line count를 100-150으로 유지하고 archive heading/order 보존을 검증한다.
