# Codex Goal — 환세취호전 웹 포팅

## 현재 정리 기준

- 이 파일은 장기 목표/작업 이력도 포함한다. 삭제, 폐기, active surface
  판단은 `docs/REVIEW_CLEANUP.md` 와 `docs/CLEANUP_INVENTORY.md` 를 우선한다.
  아래 과거 항목에는 이미 제거된 페이지나 prototype 표면이 남아 있을 수 있다.
- 2026-06-24 기준 `web/object_position_review.html` 은 legacy candidate-only 좌표 overlay라 삭제했다. 이후 active web/tools/out 표면에서는 이 페이지를 되살리지 않는다.
- 오브젝트/문/상자/NPC/`map_*3` 위치 근거는 `web/map3_active_initializer_review.html`, `out/active_object_resource_slot_review.html`, `out/active_object_bounds_semantics_review.html`, `web/map3_projection_binding_review.html`, `web/scene_event_coordinate_semantics_review.html` 을 기준으로 본다.
- candidate browser smoke raw 파일들은 `out/candidate_browser_smoke_summary.*`
  기준으로 surface consumer 0개 상태다. 즉 web/build/audit 표면은 raw smoke
  대신 compact summary 를 사용해야 하며, raw smoke 는 verifier 출력물과
  summary-generator 입력으로만 유지한다.
- `out/save_point_candidates.*`, `out/event_object_branch_state_candidate_links.*`
  는 active evidence summary 로 유지한다.

## 현재 상태 (Shelley 가 끝낸 준비 작업)

`/home/exedev/hwanse/` 작업폴더 구조:

```
GENSE.FLD MIDDATA.MLK PCMDATA.WLK Hwanse2.exe  ← 원본 게임 파일
SAVEDATA/, SaveData/                            ← 빈 세이브 슬롯 디렉토리
docs/
  INVENTORY.md     파일 인벤토리 + 분류
  FORMATS.md       3종 아카이브 컨테이너 포맷 + .cns 변종 매트릭스
  GOAL.md          (this file)
tools/
  extract_fld.py   GENSE.FLD → extract_fld/*.cns
  extract_wlk.py   PCMDATA.WLK → extract_wlk/*.wav (직접 재생 가능)
  extract_mlk.py   MIDDATA.MLK → extract_mlk/*.mid (직접 재생 가능)
  decode_cns.py    CNS 압축 해제 + 이미지 PNG 변환
  export_map_js.py CNS 맵 레이아웃 → 브라우저용 JS
  build_web_assets.py 현재 웹 프로토타입 자산 생성
  render_map_preview.py 맵 프리뷰 PNG 생성
  classify_cns_payloads.py CNS payload 이미지/타일맵 분류
  probe_tile_mapping.py 타일 좌표계 후보 비교 렌더링
  verify_web_assets.py 웹 자산/맵 메타데이터 검증
  probe_exe_cns_groups.py 실행파일 내 CNS 파일명 그룹 탐색
  probe_scene_coordinate_candidates.py 장면 레코드 좌표형 포인터 후보 스캔
extract_fld/  377 .cns
extract_wlk/  54 .wav
extract_mlk/  20 .mid
```

**확정된 사실**
1. `GENSE.FLD` = `"FLDF0100"` + u32 count + (12B name + u32 off + u32 size) * count.
2. `PCMDATA.WLK` = `"WLKF0200"` + u16 count + u16 archive flags + 22B 엔트리(샘플레이트/gain metadata 포함) — 54개 mono PCM. entry flags bit7 이 켜진 7개는 16-bit signed PCM, 나머지는 8-bit unsigned PCM 이며 현재 분포는 flags `0x00` 43개, `0x20` 4개, `0x80` 7개다. 확정 표는 `out/audio_archive_manifest.*` 에 있으며 사용자-facing 번호는 EXE zero-based WLK id `00..53` 이다. 예를 들어 WLK id `45` 는 `extract_wlk/45.wav` 를 직접 가리킨다.
3. `MIDDATA.MLK` = u8 count + 9B 엔트리(flag/off/size) — 20개 Standard MIDI Format 0. 확정 표는 `out/audio_archive_manifest.*` 에 있다.
4. `.cns` 는 CNS 압축 스트림이며, 압축 해제 뒤 이미지 또는 맵 레이아웃 페이로드로 나뉜다. 자세한 내용은 `docs/CNS_FORMAT.md`, `docs/FORMATS.md`.

**현재 수동 작업 기준**
- 2026-06-11 WLK/MLK 복원은 `tools/audio_archive_manifest.py` 와 `out/audio_archive_manifest.*` 기준으로 완료 처리한다. 별도 probe 와 대체 preview 계열 우회는 복원 경로에서 제거한다. 현재 MIDI 웹 재생 검증 경로는 `web/midi_bgm_test.html` + `web/engine/audio/midi_bgm_player.js` 의 WebAudio GM Lite baseline 이며, 선택형 SF2/SF3/Web MIDI 경로는 lazy-load/수동 선택으로 분리한다. 구현/검증 상세는 `docs/AUDIO_ARCHIVE.md` 와 `out/midi_bgm_test_browser_smoke.*` 에 둔다.
- 2026-06-12 수동 작업 기준으로 원본 `savedat*.dat` 분석은 active 작업에서 제외한다. 실제 EXE 이벤트/맵/전투/상태 실행 구조가 먼저 잡히기 전에는 savedata offset, selector `2:0`, selected-root, public/synthetic save route proof 를 진행하지 않는다. 재개 조건과 남길 단서는 `docs/SAVEDATA_PARKED.md` 에 둔다.

**미해결 (Codex 가 진행할 부분)**
- 충돌/통행 가능 타일, 맵 전환 트리거, 이벤트/대화 데이터 위치 식별.
- `Hwanse2.exe` 실행 흐름 분석으로 DInput 입력 처리, 맵 이벤트, 전투 진입 호출 패턴 추적.
- 웹 런타임을 단순 이동 프로토타입에서 실제 게임 진행 구조로 확장.

## 작업 순서 (사용자가 정의)

1. ✅ 파일 인벤토리 분석
2. 🟡 바이너리 포맷 추정 — 컨테이너 3종과 확인된 `.cns` 이미지 포맷 완료, 변종 추가 검증 필요
3. ✅ 리소스 추출기 작성 — 컨테이너용 완료, `.cns` 디코더 추가 (`tools/decode_cns.py`)
4. ✅ 이미지/팔레트/사운드 뷰어 작성 — `legacy aggregate asset workbench (removed)`, map/collision review, character frame review, WebKit detailed-review smoke 로 검증
5. 🟡 원본 실행 흐름 분석 (`Hwanse2.exe` 디스어셈블; DirectDraw/DInput 기초 호출 패턴 추적 완료, 이벤트/전투 진입 호출 패턴은 진행 중)
6. 🟡 웹 Canvas 기반 런타임 구현 — 정적 HTML 프로토타입 시작, `tools/build_web_assets.py` 로 자산 생성 가능
7. ✅ 첫 화면(타이틀) 또는 맵 한 장 재현 — `out/title.png`, `out/title_start_browser_summary.*`, `out/maps_runtime_chunks/map1_02b.js`, `out/maps_runtime_chunks/map1_01a.js`, `web/index.html`
8. 🟡 입력/이동/대화/전투 등 기능 확장 — 방향키 이동 프로토타입 시작

## Codex 에게 줄 다음 골 (제안)

> "환세취호전 맵 진행에 필요한 비그래픽 데이터를 식별하라.
> 1차 목표: 현재 Canvas 프로토타입의 `map1_01a`, `map1_02b`, `map3_09a` 에서 통행 가능 영역/충돌/우선순위 정보를 추정하고,
> 원본 데이터 또는 실행파일에서 그 근거를 찾아 문서화하라.
> 2차 목표: 맵 전환 지점, 이벤트/대화 트리거, 시작 좌표를 찾고 `web/index.html` 런타임에 최소한의 전환 처리를 붙여라.
> 결과물: 포맷 문서 갱신, 필요한 추출/변환 도구, 브라우저에서 걷고 맵이 전환되는 프로토타입."

진행 결과:
- 2026-06-11 08:21 KST 운영 상태를 `/goal` 장기 진행에서 수동 요청 모드로 전환했다. 이는 실제 goal 완료가 아니며, `out/goal_completion_checklist.json` 의 `achieved=false`/`routePromotionStatus=blocked` 와 `out/completion_audit.json` 의 `achieved=false` 상태를 그대로 유지한다. 이후 작업은 `docs/HANDOFF.md` 와 이 파일을 memory 로 삼고, 사용자가 요청하는 작은 범위의 수동 작업 단위로만 진행한다. `update_goal(status="complete")` 는 향후 fresh completion audit 이 strict source coordinate, tile hotspot confirmation, selected-root execution ref, real selector `2:0` captured savedata, runtime trace/equivalent selected-root proof 를 실제로 만족하기 전까지 호출하지 않는다.
- 현재 관리 대시보드 기준 현재값(2026-06-11 08:00 KST): `web/index.html` 최근 검증 작업 18행, `web/index.html` 의 system offset 최근 작업 행은 일반 `system_review.html` 링크와 `system_review.html#systemOffsetRouteControlMatrixPanel`/`system_review.html#systemOffsetValueMatrixPanel`/`system_review.html#systemOffsetPairDecodePanel`/`system_review.html#systemOffsetEquipmentNameCoveragePanel`/`system_review.html#systemOffsetTargetedDeltaPlanPanel` 직접 링크를 함께 제공, `web/index.html` 의 battle numeric 행은 `battle_analysis.html#battleNumericBoundaryPanel`, `../out/original_battle_numeric_context.html`, `battle_analysis.html#numericTriagePanel` 직접 링크를 제공, `web/progress.html#evidenceHandoffPanel` handoff 27행(local 23 / external 4), `web/progress.html#localRoadmapQueuePanel` 로컬 확장 후보 6행(event/dialogue/object runtime boundary, battle numeric boundary/triage, route-control/value/equipment-item name coverage/targeted delta, monster all/candidate 직접 링크 포함), `web/progress.html#runtimeSliceMatrixPanel` 브라우저 런타임 후보 16행, `web/format_review.html#opcodeLayoutGapPanel` event VM operand/layout gap 6행, `web/system_review.html#systemOffsetTriageQueuePanel` 세이브 오프셋 triage 6행, `web/system_review.html#systemOffsetClusterPanel` 세이브 unknown range cluster 4 bucket/87 range, `web/system_review.html#systemOffsetRouteControlMatrixPanel` route selector/control 값 matrix 7행, `web/system_review.html#systemOffsetValueMatrixPanel` inventory/equipment 후보 값 matrix 4행, `web/system_review.html#systemOffsetPairDecodePanel` inventory/equipment pair decode 2행(1/0-based item hit 열 포함), `web/system_review.html#systemOffsetEquipmentNameCoveragePanel` 장비/아이템 이름 후보 coverage 2행(item hit 1/2), `web/system_review.html#systemOffsetTargetedDeltaPlanPanel` 장비/아이템 targeted delta 계획 5행, `web/system_review.html#systemOffsetTargetedDeltaIntakePanel` targeted delta intake 5행(provided 0 / missing 5 / manifest 없음), `out/savedata_targeted_delta_intake.md`/`.html`, `web/progress.html#verificationLedgerPanel` 6/6 passed, `web/progress.html#wrapChecklistPanel` 7단계. 아래의 이전 2026-06-11 항목에 남아 있는 11행/22행/local 18, 14행/25행/local 21, 15행/26행/local 22, 16행, 17행 같은 수치는 해당 slice 작성 당시의 중간값이며, 최신 기준은 이 줄과 최상단 runtime matrix/system offset triage/system offset cluster/route-control matrix/value matrix/pair decode/equipment/item name coverage/targeted delta/event runtime/format opcode layout/local roadmap/completion audit/menu/object/dialogue runtime boundary 항목을 우선한다.
- 2026-06-11 08:00 KST targeted savedata delta intake 를 추가했다. `tools/summarize_savedata_targeted_delta_intake.py` 는 `web/system_review.html#systemOffsetTargetedDeltaPlanPanel` 의 5개 캡처 단위를 실제 before/after save pair intake 상태로 바꿔 `out/savedata_targeted_delta_intake.json`/`.md`/`.html` 을 생성한다. 현재 manifest 는 `data/targeted_savedata/manifest.json`, found true, provided capture pairs 0, valid capture pairs 0, missing capture rows 5, completion status `missing-targeted-saves` 이다. `web/system_review.html#systemOffsetTargetedDeltaIntakePanel` 은 이 상태를 일반 표로 보여주고 `../out/savedata_targeted_delta_intake.html` 로 연결한다. `HWANSE_LAST_SYSTEM_REVIEW_RENDER` 는 `browserSystemOffsetTargetedDeltaIntakeImplemented=True`, `systemOffsetTargetedDeltaIntakeRowCount=5`, `systemOffsetTargetedDeltaIntakeProvidedCapturePairCount=0`, `systemOffsetTargetedDeltaIntakeValidCapturePairCount=0`, `systemOffsetTargetedDeltaIntakeMissingCapturePairCount=5`, `systemOffsetTargetedDeltaIntakeManifestFound=True`, `systemOffsetTargetedDeltaIntakeNonPromoting=True` 를 남긴다. 이는 다음 수동 savedata 캡처가 들어오면 바로 비교하기 위한 준비 산출물이며, changed savedata 자체, original save writer proof, selector `2:0` captured savedata, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 07:48 KST pre-wrap audit snapshot 을 확인했다. `out/goal_completion_checklist.json` 은 `achieved=false`, `routePromotionStatus=blocked` 이고, `out/completion_audit.json` 도 `achieved=false`, confirmed route progress `2/174` maps 를 유지한다. Hard missing evidence 는 strict source coordinate, tile hotspot confirmation, selected-root execution ref, real selector `2:0` captured savedata, runtime trace/equivalent selected-root proof 5개 그대로이며, external input checklist 는 `real-selector-2-0-save` missing, `normal-route-runtime-trace` blocked-by-environment, `strict-source-hotspot` missing 3행이다. 이는 `docs/HANDOFF.md` 의 pre-wrap snapshot 에도 기록했으며, 최근 추가한 targeted delta 계획은 changed-save 캡처 큐일 뿐 route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 07:52 KST wrap verification 을 완료했다. `py_compile`, `git diff --check`, `tools/verify_runtime_http.py --base http://127.0.0.1:8013`, `tools/verify_web_assets.py`, `xvfb-run -a python3 tools/verify_home_landing_browser.py --base http://127.0.0.1:8013` 가 모두 통과했고, fixed test web port `8013` 에서 `python3 -m http.server 8013` 이 유지되는 것을 확인했다. 이 검증은 관리/문서 전환 마무리이며, completion audit 의 `achieved=false`/route-blocked 상태를 바꾸지 않는다.
- 2026-06-11 전투 수치/공식 직접 링크를 보강했다. `web/battle_analysis.html` 의 `원본 전투 수치/공식 경계` section 에 `battleNumericBoundaryPanel` anchor 를 붙이고, 16행 `숫자 후보 triage` 표에는 `numericTriagePanel` anchor 를 붙였다. `web/index.html` 최근 검증 작업 battle numeric 행은 `battle_analysis.html#battleNumericBoundaryPanel`, `../out/original_battle_numeric_context.html`, `battle_analysis.html#numericTriagePanel` 로 바로 들어가고, `web/progress.html#localRoadmapQueuePanel` 과 `web/progress.html#evidenceHandoffPanel` 도 같은 세부 링크를 노출한다. `HWANSE_LAST_HOME_RENDER` 는 `recentWorkBattleNumericHref="battle_analysis.html#battleNumericBoundaryPanel"`, `recentWorkBattleNumericSourceHref="../out/original_battle_numeric_context.html"`, `recentWorkBattleNumericTriageHref="battle_analysis.html#numericTriagePanel"` 를 남기고, `HWANSE_LAST_PROGRESS_RENDER` 는 `progressLocalRoadmapQueueBattleBoundaryHref="battle_analysis.html#battleNumericBoundaryPanel"`, `progressLocalRoadmapQueueBattleTriageHref="battle_analysis.html#numericTriagePanel"`, `progressEvidenceHandoffBattleNumericBoundaryPanelHref="battle_analysis.html#battleNumericBoundaryPanel"`, `progressEvidenceHandoffBattleNumericTriageHref="battle_analysis.html#numericTriagePanel"` 를 남긴다. `HWANSE_LAST_BATTLE_REVIEW_RENDER` 는 `battleNumericBoundaryPanelHref="battle_analysis.html#battleNumericBoundaryPanel"`, `battleNumericTriagePanelHref="battle_analysis.html#numericTriagePanel"` 를 남긴다. 이는 roadmap 8 전투 수치 후보를 일반 웹 관리 화면에서 바로 추적하기 위한 UX/진행 보강이며, descriptor-local number 를 enemy row/stat/reward/formula, original battle-entry proof, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 savedata unknown range cluster 산출물을 추가했다. `tools/summarize_savedata_offset_triage_clusters.py` 는 `out/savedata_sample_coverage.json` 과 `out/savedata_sample_deltas.json` 의 known semantic fields, route-critical offsets, unknown varying ranges 를 읽어 `out/savedata_offset_triage_clusters.json`/`.md`/`.html` 을 생성하고, `tools/build_web_assets.py` 도 이 산출물을 재생성한다. 현재 결과는 known semantic bytes 160, unknown varying ranges 87, unknown varying bytes 248, route-critical offsets 11, bucket 4개이며, `skill-status-candidate` 45 ranges/109 bytes, `character-status-candidate` 31 ranges/93 bytes, `route-selector-control` 7 ranges/10 bytes, `inventory-equipment-candidate` 4 ranges/36 bytes 로 정렬된다. 같은 산출물은 route selector/control 후보 7개 range 의 public sample 값 matrix 와 inventory/equipment 후보 4개 range 의 public sample 값 matrix 를 포함하며, 6개 sample 기준 inventory/equipment distinct range 4개, longest range `0x0022-0x0037` 을 기록한다. `0x0022-0x0037` 은 selector `0:0`/`1:0` 에서는 22바이트 zero 값이고 selector `22:0` 에서는 `0a 01 ... 1f 01` 같은 2바이트 pair 패턴으로 갈라져 다음 장비/아이템 후보 확인의 우선순위가 됐다. 후속으로 text table 의 `equipment` 18개 이름과 item table 이름을 사용한 pair decode 후보도 추가해 `0x0022-0x0037` 11 pairs 중 1-based equipment id hit 8개, 전체 pair decode row 2개, 1-based equipment hit 합계 9개, 0-based equipment hit 합계 9개, 1-based item hit 합계 1개, 0-based item hit 합계 2개를 기록한다. 대표 1-based 장비 이름 후보는 `청룡도`, `불타는 마검 !`, `그레이트소드 )`, `마인아수라 2`, `투신의 갑옷` 이고 대표 아이템 이름 후보는 `약초` 이지만 일부 id 는 미매핑이고 one-based/zero-based ambiguity 가 있어 후보로만 둔다. `web/system_review.html#systemOffsetClusterPanel` 은 bucket 요약을, `web/system_review.html#systemOffsetRouteControlMatrixPanel` 은 selector `2:0` captured savedata 요구를 유지한 route-control 7행 value matrix 를, `web/system_review.html#systemOffsetValueMatrixPanel` 은 4행 inventory/equipment value matrix 를, `web/system_review.html#systemOffsetPairDecodePanel` 은 2행 pair decode 후보와 장비/아이템 hit 를, `web/system_review.html#systemOffsetEquipmentNameCoveragePanel` 은 같은 2행을 메뉴 장비 후보/런타임 장비 링크 및 아이템 이름 후보와 연결하는 coverage 표로 보여준다. `web/progress.html#localRoadmapQueuePanel` 의 system offset row 는 일반 `system_review.html` 링크를 유지하면서 `system_review.html#systemOffsetRouteControlMatrixPanel`, `system_review.html#systemOffsetValueMatrixPanel`, `system_review.html#systemOffsetEquipmentNameCoveragePanel` 직접 링크를 제공하고, `web/progress.html#evidenceHandoffPanel` 의 system offset row 는 value matrix 직접 링크를 제공한다. `web/index.html` 의 최근 검증 작업 system offset 행도 `system_review.html#systemOffsetRouteControlMatrixPanel`, `system_review.html#systemOffsetValueMatrixPanel` 직접 링크와 `route-control 7행`, `value matrix 4행`, `pair decode 2행`, `equipment/item name coverage 2행`, `item hit 1/2` 설명을 노출한다. `HWANSE_LAST_SYSTEM_REVIEW_RENDER` 는 `browserSystemOffsetClusterReviewImplemented=True`, `systemOffsetClusterBucketCount=4`, `systemOffsetClusterRangeCount=87`, `systemOffsetClusterByteCount=248`, `systemOffsetClusterCandidateRangeCount=80`, `systemOffsetClusterPartialRangeCount=7`, `systemOffsetClusterRouteSelectorControlRangeCount=7`, `systemOffsetClusterInventoryEquipmentRangeCount=4`, `systemOffsetClusterSkillStatusRangeCount=45`, `systemOffsetClusterCharacterStatusRangeCount=31`, `systemOffsetClusterNonPromoting=True`, `browserSystemOffsetRouteControlMatrixImplemented=True`, `systemOffsetRouteControlMatrixRowCount=7`, `systemOffsetRouteControlMatrixDistinctRangeCount=7`, `systemOffsetRouteControlMatrixRequiresSelector20Save=True`, `systemOffsetRouteControlMatrixNonPromoting=True`, `browserSystemOffsetValueMatrixImplemented=True`, `systemOffsetValueMatrixRowCount=4`, `systemOffsetValueMatrixSampleCount=6`, `systemOffsetValueMatrixDistinctRangeCount=4`, `systemOffsetValueMatrixLongestRangeHex="0x0022-0x0037"`, `systemOffsetValueMatrixNonPromoting=True`, `browserSystemOffsetPairDecodeImplemented=True`, `systemOffsetPairDecodeRowCount=2`, `systemOffsetPairDecodeOneBasedHitCount=9`, `systemOffsetPairDecodeZeroBasedHitCount=9`, `systemOffsetPairDecodeOneBasedItemHitCount=1`, `systemOffsetPairDecodeZeroBasedItemHitCount=2`, `systemOffsetPairDecodeLongestRangeHex="0x0022-0x0037"`, `systemOffsetPairDecodeCandidateBasis="one-based equipment table candidate"`, `systemOffsetPairDecodeNonPromoting=True`, `browserSystemOffsetEquipmentNameCoverageImplemented=True`, `systemOffsetEquipmentNameCoverageRowCount=2`, `systemOffsetEquipmentNameCoverageOneBasedHitCount=9`, `systemOffsetEquipmentNameCoverageZeroBasedHitCount=9`, `systemOffsetEquipmentNameCoverageOneBasedItemHitCount=1`, `systemOffsetEquipmentNameCoverageZeroBasedItemHitCount=2`, `systemOffsetEquipmentNameCoverageMenuHref="menu_review.html?panel=equipment"`, `systemOffsetEquipmentNameCoverageRuntimeHref="game.html?map=map2_02d&startTile=11%2C12&publicSave=flack3r-savedat2&menu=equipment"`, `systemOffsetEquipmentNameCoverageNonPromoting=True` 를 남기고, `HWANSE_LAST_PROGRESS_RENDER` 는 `progressLocalRoadmapQueueSystemRouteControlHref="system_review.html#systemOffsetRouteControlMatrixPanel"`, `progressLocalRoadmapQueueSystemValueMatrixHref="system_review.html#systemOffsetValueMatrixPanel"`, `progressLocalRoadmapQueueSystemNameCoverageHref="system_review.html#systemOffsetEquipmentNameCoveragePanel"`, `progressEvidenceHandoffSystemOffsetValueMatrixHref="system_review.html#systemOffsetValueMatrixPanel"` 를, `HWANSE_LAST_HOME_RENDER` 는 `recentWorkSystemOffsetRouteControlHref="system_review.html#systemOffsetRouteControlMatrixPanel"`, `recentWorkSystemOffsetValueMatrixHref="system_review.html#systemOffsetValueMatrixPanel"` 를 남긴다. `tools/verify_home_landing_browser.py` 의 8013 smoke summary 는 `systemOffsetClusters=4/87`, `systemOffsetRouteControls=7`, `systemOffsetValues=4`, `systemOffsetPairs=2`, `systemOffsetNames=2` 를 기록하고, DOM/marker 검증은 item hit 1/2 와 `약초` 후보를 확인한다. `tools/verify_web_assets.py` 는 정적 구조/marker 를 검증한다. 이는 roadmap 8 에서 장비/상태/story 오프셋 후보를 proximity/delta 기준으로 좁히는 로컬 분석 산출물이며, original writer proof, selector `2:0` captured savedata, selected-root runtime execution, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 관리 홈 system offset 직접 링크를 보강했다. `web/index.html` 의 최근 검증 작업 system offset 행은 이제 일반 `system_review.html` 링크에 더해 `system_review.html#systemOffsetRouteControlMatrixPanel`, `system_review.html#systemOffsetValueMatrixPanel`, `system_review.html#systemOffsetPairDecodePanel`, `system_review.html#systemOffsetEquipmentNameCoveragePanel`, `system_review.html#systemOffsetTargetedDeltaPlanPanel` 로 바로 들어간다. `HWANSE_LAST_HOME_RENDER` 는 `recentWorkSystemOffsetPairDecodeHref="system_review.html#systemOffsetPairDecodePanel"`, `recentWorkSystemOffsetNameCoverageHref="system_review.html#systemOffsetEquipmentNameCoveragePanel"`, `recentWorkSystemOffsetTargetedDeltaHref="system_review.html#systemOffsetTargetedDeltaPlanPanel"` 를 추가로 남긴다. 이는 일반 관리자 홈에서 route-control/value/pair/name coverage/targeted delta 계획을 바로 확인하기 위한 UX 보강이며, original save writer proof, selector `2:0` captured savedata, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 system review 에 장비/아이템 targeted delta 계획을 추가했다. `web/system_review.html#systemOffsetTargetedDeltaPlanPanel` 은 item count delta, equipment ownership delta, equip/unequip slot delta, status/story negative control, route-selector negative control 5행으로 다음 캡처 단위를 정리한다. 각 행은 `0x006d-0x006e`, `0x0022-0x0037`, `0x005c-0x0066`, status/character 후보 range, route selector/control 후보 range 를 어떤 changed savedata와 비교해야 하는지 보여주며, `system_review.html#systemOffsetPairDecodePanel`, `system_review.html#systemOffsetEquipmentNameCoveragePanel`, `game.html?...menu=equipment`, `game.html?...menu=shop` 같은 검토 링크를 제공한다. `web/progress.html#localRoadmapQueuePanel` 의 save/equipment row 도 `system_review.html#systemOffsetTargetedDeltaPlanPanel` 로 직접 들어가며, `HWANSE_LAST_SYSTEM_REVIEW_RENDER` 는 `browserSystemOffsetTargetedDeltaPlanImplemented=True`, `systemOffsetTargetedDeltaPlanRowCount=5`, `systemOffsetTargetedDeltaPlanRequiresChangedSaves=True`, `systemOffsetTargetedDeltaPlanNonPromoting=True` 를, `HWANSE_LAST_PROGRESS_RENDER` 는 `progressLocalRoadmapQueueSystemTargetedDeltaPlanHref="system_review.html#systemOffsetTargetedDeltaPlanPanel"` 를 남긴다. 이는 다음 수동 savedata 캡처를 구조화하는 roadmap 8 로컬 진행 보강이며, changed savedata 자체, original save writer proof, selector `2:0` captured savedata, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 system review 에 세이브 오프셋 triage 큐를 추가했다. `web/system_review.html#systemOffsetTriageQueuePanel` 은 기존 `세이브 장비/상태 오프셋 경계` 를 다음 로컬 작업 단위로 풀어 known semantic calibration, route-critical selector gap, equipment ownership offsets, status flag offsets, story/event writer offsets, unknown varying range clusters 6행으로 보여준다. 현재 요약은 `6 local offset triage rows`, grounded 1, partial 1, candidate 1, missing 3, non-promoting 이며, known semantic bytes 160, unknown varying ranges 87, route-critical offsets 11, selector `2:0` expected missing 1, equipment offsets unmapped 상태를 유지한다. `HWANSE_LAST_SYSTEM_REVIEW_RENDER` 는 `browserSystemOffsetTriageQueueImplemented=True`, `systemOffsetTriageQueueRowCount=6`, `systemOffsetTriageQueueGroundedRowCount=1`, `systemOffsetTriageQueuePartialRowCount=1`, `systemOffsetTriageQueueCandidateRowCount=1`, `systemOffsetTriageQueueMissingRowCount=3`, `systemOffsetTriageQueueKnownSemanticByteCount=160`, `systemOffsetTriageQueueUnknownVaryingRangeCount=87`, `systemOffsetTriageQueueRouteCriticalOffsetCount=11`, `systemOffsetTriageQueueRouteCriticalExpectedMissingCount=1`, `systemOffsetTriageQueueEquipmentOffsetsUnmapped=True`, `systemOffsetTriageQueueStatusFlagsMissing=True`, `systemOffsetTriageQueueStoryFlagsMissing=True`, `systemOffsetTriageQueueNonPromoting=True` 를 남긴다. `tools/verify_home_landing_browser.py` 는 8013 browser smoke 에서 DOM/marker 를 검증하고, `tools/verify_web_assets.py` 는 정적 구조를 검증한다. 이는 route proof 에 매몰되지 않고 roadmap 8 의 save/equipment/status offset 후보를 다음 로컬 확인 순서로 정리하는 관리자 진행 보강이며, original equipment ownership offsets, status/story writer proof, selector `2:0` captured savedata, selected-root runtime execution, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 progress 화면에 브라우저 런타임 후보 매트릭스를 추가하고 홈 최근 검증 작업에도 노출했다. `web/progress.html#runtimeSliceMatrixPanel` 은 홈의 접힌 `보조 런타임 실행 링크` 16개를 타이틀, 필드 이동, 대사, 전투, zk_big 전투, 세이브, 오브젝트, 상점, 동료, 기술, 장비, 상태, 진행, 스토리, 확정 전환, routeAssist 행으로 풀어 보여준다. 현재 요약은 16/16 browser runtime candidates, browser verified 2, prototype 9, browser-local 3, partial 1, trial only 1, non-promoting 이다. `web/index.html` 최근 검증 작업 표는 `브라우저 런타임 후보 매트릭스` 행을 추가해 18행이 되었고, `HWANSE_LAST_HOME_RENDER` 는 `recentWorkRowCount=18`, `recentWorkRuntimeMatrixHref="progress.html#runtimeSliceMatrixPanel"` 를 남긴다. `HWANSE_LAST_PROGRESS_RENDER` 는 `browserProgressRuntimeSliceMatrixImplemented=True`, `progressRuntimeSliceMatrixRowCount=16`, `progressRuntimeSliceMatrixVisibleRowCount=16`, `progressRuntimeSliceMatrixBrowserVerifiedCount=2`, `progressRuntimeSliceMatrixPrototypeCount=9`, `progressRuntimeSliceMatrixBrowserLocalCount=3`, `progressRuntimeSliceMatrixPartialCount=1`, `progressRuntimeSliceMatrixTrialOnlyCount=1`, `progressRuntimeSliceMatrixNonPromoting=True`, `progressRuntimeSliceMatrixTitleHref="game.html?game=1"`, `progressRuntimeSliceMatrixFieldHref="game.html?map=map1_02b&startTile=11%2C12&collision=1&moveMs=192"`, `progressRuntimeSliceMatrixShopHref="game.html?map=map4_08n&startTile=18%2C42&menu=shop"`, `progressRuntimeSliceMatrixRouteAssistHref="game.html?map=map1_02b&startTile=11%2C12&trialTransitions=routeAssist&routeGoal=map2_18d&routeAutoSave=1"`, `progressRuntimeSliceMatrixMenuRuntimeIncluded=True`, `progressRuntimeSliceMatrixRouteAssistIncluded=True` 를 남긴다. 최신 browser smoke summary 는 `recentWorkRowCount=18`, `runtimeMatrix=16`, `progressHandoff=27/23/4`, `verificationLedger=6/6`, `wrapChecklist=7` 을 기록한다. 이는 roadmap 6 의 browser-local/prototype/trial-only 실행 후보를 일반 progress 웹뷰와 홈 최근 작업에서 바로 추적하기 위한 관리자 진행 보강이며, original runtime parity, normal route proof, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 format review 에 event VM operand/layout gap 표를 추가하고 관리 홈/progress handoff 에 노출했다. `web/format_review.html#opcodeLayoutGapPanel` 은 dispatcher table, text source opcode layout, display/cursor opcode layout, control/display opcode layout, browser replay scope, full VM decode/runtime gap 을 6행으로 분리한다. 현재 요약은 grounded 4, partial 1, missing 1, non-promoting 이며, coverage 는 dispatcher table `0x0047f1d8`, text source decoded 3/3, display/cursor decoded 1/1, control/display grounded 11/11, grounded control events 1007, browser replay opcode 4개, full instruction length false, full operand layout false, route-linked execution false 를 보여준다. `web/index.html` 최근 검증 작업 표는 `event VM operand/layout gap` 행을 추가해 16행이 되었고, `web/progress.html#evidenceHandoffPanel` 은 `format-vm-opcode-layout-gap` local evidence row 를 추가해 27행 handoff, local 23 / external 4 가 되었다. `HWANSE_LAST_FORMAT_REVIEW_RENDER` 는 `browserFormatOpcodeLayoutGapImplemented=True`, `formatOpcodeLayoutGapRowCount=6`, `formatOpcodeLayoutGapGroundedRowCount=4`, `formatOpcodeLayoutGapPartialRowCount=1`, `formatOpcodeLayoutGapMissingRowCount=1`, `formatOpcodeLayoutGapTextSourceDecoded=True`, `formatOpcodeLayoutGapControlOpcodeCount=11`, `formatOpcodeLayoutGapGroundedControlEventCount=1007`, `formatOpcodeLayoutGapBrowserReplayOpcodeCount=4`, `formatOpcodeLayoutGapFullInstructionDecoded=False`, `formatOpcodeLayoutGapFullOperandDecoded=False`, `formatOpcodeLayoutGapRouteLinkedExecution=False`, `formatOpcodeLayoutGapNonPromoting=True` 를 남긴다. `HWANSE_LAST_HOME_RENDER` 는 `recentWorkFormatOpcodeLayoutHref="format_review.html#opcodeLayoutGapPanel"`, `HWANSE_LAST_PROGRESS_RENDER` 는 `progressEvidenceHandoffFormatOpcodeLayoutGapIncluded=True`, `progressEvidenceHandoffFormatOpcodeLayoutGapHref="format_review.html#opcodeLayoutGapPanel"` 를 남긴다. `web/progress.html#localRoadmapQueuePanel` 의 roadmap 2 링크도 이 panel 로 들어가게 바꿨다. 이는 roadmap 2 의 다음 로컬 작업 단위를 opcode coverage 와 promotion gate 사이에서 바로 읽게 하는 관리자 진행 보강이며, full VM decode/runtime, route-linked dispatch, story mutation, event-driven battle entry, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 progress 화면에 로컬 확장 큐를 추가했다. `web/progress.html#localRoadmapQueuePanel` 은 route proof 외부 입력 없이도 이어갈 수 있는 roadmap 2/5/6/8 후보를 event VM operand/layout 확대, 원본 실행 흐름 경계 보강, 브라우저 runtime 후보 기능 확장, 전투 수치/공식 후보 좁히기, 세이브 장비/상태 오프셋 후보 좁히기, 몬스터 공격/전투 역링크 정리 6행으로 분리한다. 각 행은 `format_review.html#opcodeLayoutGapPanel`, `event_review.html#eventRuntimeBoundaryPanel`, `dialogue_review.html#dialogueReplayBoundaryPanel`, `object_position_review.html#objectRuntimeBoundaryPanel`, `index.html#runtimeUtilityDetails`, `battle_analysis.html`, `battle_analysis.html#battleNumericBoundaryPanel`, `battle_analysis.html#numericTriagePanel`, `system_review.html`, `system_review.html#systemOffsetRouteControlMatrixPanel`, `system_review.html#systemOffsetValueMatrixPanel`, `system_review.html#systemOffsetEquipmentNameCoveragePanel`, `monster_review.html?scope=all`, `monster_review.html?scope=candidate` 같은 대표 화면으로 연결하고, full original VM, route-linked dispatch, original runtime parity, enemy/reward table/formula, status/story writer, original enemy AI proof 없이는 원본 parity/route proof 로 승격하지 않는 경계를 명시한다. `HWANSE_LAST_PROGRESS_RENDER` 는 `browserProgressLocalRoadmapQueueImplemented=True`, `progressLocalRoadmapQueueRowCount=6`, `progressLocalRoadmapQueueVisibleRowCount=6`, `progressLocalRoadmapQueueRouteProofSeparated=True`, `progressLocalRoadmapQueueRoadmap2Included=True`, `progressLocalRoadmapQueueRoadmap5Included=True`, `progressLocalRoadmapQueueRoadmap6Included=True`, `progressLocalRoadmapQueueRoadmap8Included=True`, `progressLocalRoadmapQueueFormatHref="format_review.html#opcodeLayoutGapPanel"`, `progressLocalRoadmapQueueEventRuntimeHref="event_review.html#eventRuntimeBoundaryPanel"`, `progressLocalRoadmapQueueDialogueReplayHref="dialogue_review.html#dialogueReplayBoundaryPanel"`, `progressLocalRoadmapQueueObjectRuntimeHref="object_position_review.html#objectRuntimeBoundaryPanel"`, `progressLocalRoadmapQueueRuntimeHref="index.html#runtimeUtilityDetails"`, `progressLocalRoadmapQueueBattleHref="battle_analysis.html"`, `progressLocalRoadmapQueueBattleBoundaryHref="battle_analysis.html#battleNumericBoundaryPanel"`, `progressLocalRoadmapQueueBattleTriageHref="battle_analysis.html#numericTriagePanel"`, `progressLocalRoadmapQueueSystemHref="system_review.html"`, `progressLocalRoadmapQueueSystemRouteControlHref="system_review.html#systemOffsetRouteControlMatrixPanel"`, `progressLocalRoadmapQueueSystemValueMatrixHref="system_review.html#systemOffsetValueMatrixPanel"`, `progressLocalRoadmapQueueSystemNameCoverageHref="system_review.html#systemOffsetEquipmentNameCoveragePanel"`, `progressLocalRoadmapQueueMonsterAllHref="monster_review.html?scope=all"`, `progressLocalRoadmapQueueMonsterCandidateHref="monster_review.html?scope=candidate"` 를 남긴다. 이는 route/exit proof 에 매몰되지 않고 2/5/6/8번 로드맵을 순차적으로 이어가기 위한 관리자 진행 큐이며, hard blocker 5개, route promotion 또는 completion audit 완료를 대체하지 않는다.
- 2026-06-11 관리 홈/progress handoff 에 완료 감사 상태를 노출했다. `web/index.html` 최근 검증 작업 표는 `완료 감사 상태` 행을 추가해 `completion_review.html` 로 바로 들어가게 했고, `web/progress.html#evidenceHandoffPanel` 은 `completion-audit-status` local evidence row 를 추가했다. 이 행은 completion proof matrix 8행, passed 3, partial 1, blocked 2, missing 2, `achieved=false`, `route promotion blocked`, hard missing 5개를 보여주되 browser-local completion/clear 를 원본 full-game completion 이나 goal 완료로 승격하지 않는다고 명시한다. 이후 runtime matrix/event runtime/format opcode layout gap 행까지 추가된 최신 `HWANSE_LAST_HOME_RENDER` 는 `recentWorkRowCount=18`, `recentWorkCompletionAuditHref="completion_review.html"` 을 남기고, 최신 `HWANSE_LAST_PROGRESS_RENDER` 는 `progressEvidenceHandoffRowCount=27`, `progressEvidenceHandoffLocalRowCount=23`, `progressEvidenceHandoffExternalRowCount=4`, `progressEvidenceHandoffCompletionAuditStatusIncluded=True`, `progressEvidenceHandoffCompletionAuditHref="completion_review.html"` 를 남긴다. `tools/verify_home_landing_browser.py` smoke 요약은 최신 기준 `recentWorkRowCount=18`, `progressHandoff=27/23/4` 를 기록하도록 갱신했고, `tools/verify_web_assets.py` 는 home/progress completion audit row/marker/artifact 링크를 정적으로 검증한다. 이는 사용자와 다음 AI가 목표 완료 여부를 일반 관리자 화면에서 즉시 확인하기 위한 진행 가시성 보강이며, hard blocker 5개, real selector `2:0` captured savedata, selected-root runtime trace, strict source coordinate/tile hotspot 또는 route promotion proof 를 대체하지 않는다.
- 2026-06-11 menu review 와 관리 홈/progress handoff 에 메뉴/상점 runtime boundary 를 노출했다. `web/menu_review.html#menuRuntimeBoundaryPanel` 은 candidate menu smokes, shop prototype transaction, party prototype join/trail, skill/status savedata review, equipment prototype effects, original shop/inventory/money, original equipment/status offsets, original story/party/combat runtime 을 8행으로 나눠 보여준다. 현재 요약은 passed 5, missing 3, non-promoting 이며, marker 는 `browserMenuRuntimeBoundaryImplemented=True`, `menuRuntimeBoundaryRowCount=8`, `menuRuntimeBoundaryPassedRowCount=5`, `menuRuntimeBoundaryMissingRowCount=3`, `menuRuntimeBoundaryCandidateSmokePassedCount=5`, `menuRuntimeBoundaryShopItemCount=6`, `menuRuntimeBoundaryEquipmentCandidateCount=18`, `menuRuntimeBoundarySavedatSkillLearnedCount=6`, `menuRuntimeBoundarySavedatSkillTotalCount=24`, `menuRuntimeBoundaryStatusMemberCount=3`, `menuRuntimeBoundaryOriginalShopMissing=True`, `menuRuntimeBoundaryOriginalOffsetsMissing=True`, `menuRuntimeBoundaryOriginalStoryCombatMissing=True`, `menuRuntimeBoundaryNonPromoting=True` 를 남긴다. `web/index.html` 최근 검증 작업 표는 `메뉴/상점 runtime 경계` 행을 추가해 14행이 되었고, `web/progress.html#evidenceHandoffPanel` 은 `menu-shop-runtime-boundary` local evidence row 를 추가해 25행 handoff, local 21 / external 4 가 되었다. `HWANSE_LAST_HOME_RENDER` 는 `recentWorkMenuRuntimeHref="menu_review.html#menuRuntimeBoundaryPanel"`, `HWANSE_LAST_PROGRESS_RENDER` 는 `progressEvidenceHandoffMenuRuntimeBoundaryIncluded=True`, `progressEvidenceHandoffMenuRuntimeBoundaryHref="menu_review.html#menuRuntimeBoundaryPanel"` 를 남긴다. `tools/verify_home_landing_browser.py` smoke 요약은 `menuRuntimeBoundary=8/5/3` 와 `progressHandoff=25/21/4` 를 기록하도록 갱신했고, `tools/verify_web_assets.py` 는 panel/row/home/progress marker 를 정적으로 검증한다. 이는 로드맵 5/8번의 shop/party/skill/equipment/status 후보 런타임 진행과 원본 menu/system 미확보 경계를 일반 관리자 화면에서 읽게 하는 UX/진행 가시성 보강이며, original shop dispatch, original inventory/money mutation, original equipment/status/story offsets, party/story/combat runtime proof, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 object review 와 관리 홈/progress handoff 에 세이브/오브젝트 runtime boundary 를 노출했다. `web/object_position_review.html#objectRuntimeBoundaryPanel` 은 save-point candidate index, save-point browser runtime, object inspection runtime, object collision runtime, linked dialogue/battle runtime, original save-point dispatch, original object dispatch, story/route state binding 을 8행으로 나눠 보여준다. 현재 요약은 passed 4, candidate 1, missing 3, non-promoting 이며, marker 는 `browserObjectRuntimeBoundaryImplemented=True`, `objectRuntimeBoundaryRowCount=8`, `objectRuntimeBoundaryPassedRowCount=4`, `objectRuntimeBoundaryCandidateRowCount=1`, `objectRuntimeBoundaryMissingRowCount=3`, `objectRuntimeBoundarySavePointCandidateCount=8`, `objectRuntimeBoundarySceneLinkedObjectCount=7`, `objectRuntimeBoundaryLinkedDialogueCount=3`, `objectRuntimeBoundaryBattleVictoryCount=3`, `objectRuntimeBoundaryRouteLinkedMissing=True`, `objectRuntimeBoundaryStoryFlagMissing=True`, `objectRuntimeBoundaryNonPromoting=True` 를 남긴다. `web/index.html` 최근 검증 작업 표에는 `세이브/오브젝트 runtime 경계` 링크가 있고, `web/progress.html#evidenceHandoffPanel` 은 `object-save-runtime-boundary` local evidence row 를 포함한다. 이후 메뉴/상점 runtime boundary 행이 추가되어 최신 홈/progress 행 수는 위 항목 기준이다. `HWANSE_LAST_HOME_RENDER` 는 `recentWorkObjectRuntimeHref="object_position_review.html#objectRuntimeBoundaryPanel"`, `HWANSE_LAST_PROGRESS_RENDER` 는 `progressEvidenceHandoffObjectRuntimeBoundaryIncluded=True`, `progressEvidenceHandoffObjectRuntimeBoundaryHref="object_position_review.html#objectRuntimeBoundaryPanel"` 를 남긴다. `tools/verify_home_landing_browser.py` smoke 요약은 `objectRuntimeBoundary=8/1/3` 을 기록하도록 갱신했고, `tools/verify_web_assets.py` 는 panel/row/home/progress marker 를 정적으로 검증한다. 이는 로드맵 5/8번의 save/object 후보 런타임 진행과 원본 save-point/object dispatch 미확보 경계를 일반 관리자 화면에서 읽게 하는 UX/진행 가시성 보강이며, original save-point event dispatch, original object/NPC runtime, route/story state binding, selected-root runtime proof 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 dialogue review 와 관리 홈/progress handoff 에 대사 VM replay boundary 를 노출했다. `web/dialogue_review.html#dialogueReplayBoundaryPanel` 은 dialogue storage index, candidate dialogue playback, prototype completion/title restore, branch/control replay, render/style/cursor/object replay, literal/input-wait replay, route-linked original dispatch, full original VM/story/battle 을 8행으로 나눠 보여준다. 현재 요약은 grounded 1, passed 2, partial 3, missing 2, non-promoting 이며, marker 는 `browserDialogueReplayBoundaryImplemented=True`, `dialogueReplayBoundaryRowCount=8`, `dialogueReplayBoundaryGroundedRowCount=1`, `dialogueReplayBoundaryPassedRowCount=2`, `dialogueReplayBoundaryPartialRowCount=3`, `dialogueReplayBoundaryMissingRowCount=2`, `dialogueReplayBoundaryBranchStepCount=62`, `dialogueReplayBoundaryLiteralEventCount=7`, `dialogueReplayBoundaryRouteLinkedOriginalMissing=True`, `dialogueReplayBoundaryFullOriginalVmMissing=True`, `dialogueReplayBoundaryNonPromoting=True` 를 남긴다. `web/index.html` 최근 검증 작업 표는 `대사 VM replay 경계` 행을 추가해 12행이 되었고, `web/progress.html#evidenceHandoffPanel` 은 `dialogue-vm-replay-boundary` local evidence row 를 추가해 23행 handoff, local 19 / external 4 가 되었다. `HWANSE_LAST_HOME_RENDER` 는 `recentWorkDialogueReplayHref="dialogue_review.html#dialogueReplayBoundaryPanel"`, `HWANSE_LAST_PROGRESS_RENDER` 는 `progressEvidenceHandoffDialogueReplayBoundaryIncluded=True`, `progressEvidenceHandoffDialogueReplayBoundaryHref="dialogue_review.html#dialogueReplayBoundaryPanel"` 를 남긴다. `tools/verify_home_landing_browser.py` smoke 요약은 `dialogueReplayBoundary=8/3/2` 와 `progressHandoff=23/19/4` 를 기록하고, `tools/verify_web_assets.py` 는 panel/row/home/progress marker 를 정적으로 검증한다. 이는 로드맵 5/8번의 대사/VM replay 진행과 원본 dispatch 미확보 경계를 일반 관리자 화면에서 읽게 하는 UX/진행 가시성 보강이며, route-linked original event VM execution, original story flag mutation, event-driven battle entry, full browser event VM 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 format review 에 로드맵 2 포맷 추정 ledger 를 추가했다. `web/format_review.html#roadmap2FormatLedgerPanel` 은 archive container formats, CNS decode/image payloads, tilemap/map assembly surface, savedata semantic coverage, event VM opcode subset, audio archive/title boundary, DirectX runtime surface, original collision/event semantics 를 8행으로 묶어 보여준다. 현재 요약은 grounded 2, passed 1, partial 4, blocked 1, non-promoting 이며, marker 는 `browserFormatRoadmap2LedgerImplemented=True`, `formatRoadmap2LedgerRowCount=8`, `formatRoadmap2LedgerGroundedRowCount=2`, `formatRoadmap2LedgerPassedRowCount=1`, `formatRoadmap2LedgerPartialRowCount=4`, `formatRoadmap2LedgerBlockedRowCount=1`, `formatRoadmap2LedgerCnsPayloadCount=377`, `formatRoadmap2LedgerSavedataKnownBytes=160`, `formatRoadmap2LedgerOpcodeRowCount=16`, `formatRoadmap2LedgerDirectDrawVerifiedCount=25`, `formatRoadmap2LedgerOriginalSemanticsBlocked=True`, `formatRoadmap2LedgerNonPromoting=True` 를 남긴다. `tools/verify_home_landing_browser.py` smoke 요약은 `formatLedger=8/4/1` 을 기록하고, `tools/verify_web_assets.py` 는 panel/row/marker 를 정적으로 검증한다. 이는 사용자가 로드맵 2번의 포맷 추정 진행을 포맷 검토 화면 한 곳에서 읽게 하는 관리자 UX/진행 가시성 보강이며, original collision/event semantics, selected-root execution, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 관리 홈/progress handoff 에 event VM opcode coverage 를 노출했다. `web/index.html` 의 `최근 검증된 작업` 표에 `event VM opcode coverage` 행을 추가해 `format_review.html#opcodeCoveragePanel` 로 바로 들어가게 했고, `web/progress.html#evidenceHandoffPanel` 에 `format-vm-opcode-coverage` local evidence row 를 추가했다. 이 행은 format review opcode coverage 16행, browser replay 4개, variable length 1개, literal storage 1개, dispatcher verified 상태를 보여주되 full instruction length/operand layout, route-linked event VM execution, original story flag mutation, full browser event VM 으로 승격하지 않는다고 명시한다. `HWANSE_LAST_HOME_RENDER` 는 `recentWorkRowCount=11`, `recentWorkFormatOpcodeHref="format_review.html#opcodeCoveragePanel"` 을 남기고, `HWANSE_LAST_PROGRESS_RENDER` 는 `progressEvidenceHandoffRowCount=22`, `progressEvidenceHandoffLocalRowCount=18`, `progressEvidenceHandoffFormatOpcodeCoverageIncluded=True`, `progressEvidenceHandoffFormatOpcodeCoverageHref="format_review.html#opcodeCoveragePanel"` 를 남긴다. 이는 로드맵 2번 바이너리/VM 포맷 추정의 현재 근거를 관리 홈과 progress handoff 에서 바로 확인하기 위한 관리자 UX/진행 가시성 보강이며, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 progress 08:00 KST wrap checklist 를 추가했다. 사용자가 2026-06-11 08:00 KST부터 새 broad feature work 를 멈추고 정리로 전환하라고 요청했으므로, `web/progress.html#wrapChecklistPanel` 에 `08:00 KST 마무리 체크리스트` 7행을 추가했다. 이 표는 새 대형 구현 중지, 현재 edit 마감, verification ledger 명령 재실행, `docs/HANDOFF.md`/`docs/GOAL.md` 최종 갱신, completion audit 상태 재확인, 8013 서버 유지/확인, 실제 완료 여부와 남은 external proof 보고를 순서대로 보여준다. `HWANSE_LAST_PROGRESS_RENDER` 는 `browserProgressKstWrapChecklistImplemented=True`, `progressKstWrapChecklistRowCount=7`, `progressKstWrapChecklistStartKst="2026-06-11 08:00 KST"`, `progressKstWrapChecklistFixedPortIncluded=True`, `progressKstWrapChecklistFinalReportIncluded=True` 를 남긴다. 이는 수동 전환/다음 AI 인계를 위한 운영 UX 보강이며, completion audit 완료나 route promotion proof 로 승격하지 않는다.
- 2026-06-11 progress verification ledger 를 추가했다. `web/progress.html#verificationLedgerPanel` 에 `검증/운영 ledger` 6행을 추가해 8013 고정 포트, `py_compile`, `git diff --check`, `verify_runtime_http.py --base http://127.0.0.1:8013`, `verify_web_assets.py`, `verify_home_landing_browser.py --base http://127.0.0.1:8013` 통과 상태를 한 화면에서 보게 했다. `web/index.html` 의 최근 검증 작업 progress 행도 `runtime slices/verification ledger` 를 명시하도록 갱신했다. `HWANSE_LAST_PROGRESS_RENDER` 는 `browserProgressVerificationLedgerImplemented=True`, `progressVerificationLedgerRowCount=6`, `progressVerificationLedgerPassedCount=6`, `progressVerificationLedgerFixedPort=8013`, `progressVerificationLedgerGoalAchievedFalse=True`, `progressVerificationLedgerHomeSmokeHref="../out/home_landing_browser_smoke.json"` 를 남긴다. 이는 08:00 KST 수동 전환/다음 AI 인계 때 어떤 검증이 실제로 통과했는지 웹에서 바로 확인하기 위한 운영 UX 보강이며, `achieved=false`, hard blocker 5개, external input 3개, route promotion blocked 상태를 변경하지 않는다.
- 2026-06-11 progress evidence handoff 에 홈 보조 런타임 실행 링크 근거를 추가했다. `web/progress.html#evidenceHandoffPanel` 에 `home-playable-runtime-slices` local evidence row 를 추가해 `web/index.html#runtimeUtilityDetails`, `out/home_landing_browser_smoke.json`, `out/playable_progress.json` 으로 바로 이동하게 했다. 이 행은 일반 관리 홈의 16개 browser-local runtime link(title, field walk, dialogue, battle, sprite battle, save/object/shop/party/skill/equipment/status/progress/story, confirmed transition, routeAssist)를 한 줄로 요약하되, browser-local/prototype/trial-only 실행 조각을 original event/save/battle/story runtime parity, route promotion, completion audit success 로 승격하지 않는다고 명시한다. `web/index.html` 의 quick review/progress handoff 문구도 `local 18 / external 4` 와 `22행 handoff` 로 갱신했고, `HWANSE_LAST_PROGRESS_RENDER` 는 `progressEvidenceHandoffRowCount=22`, `progressEvidenceHandoffLocalRowCount=18`, `progressEvidenceHandoffExternalRowCount=4`, `progressEvidenceHandoffPlayableSlicesIncluded=True`, `progressEvidenceHandoffPlayableSlicesHref="index.html#runtimeUtilityDetails"` 를 남긴다. 이는 사용자가 실제로 확인할 수 있는 웹 포팅 조각을 관리자 진행 화면에서 다음 작업 단위로 추적하기 위한 UX/진행 가시성 보강이며, strict hotspot coordinate, real selector `2:0` savedata, selected-root runtime trace, route promotion 또는 goal completion 으로 승격하지 않는다.
- 2026-06-11 충돌/타일 클래스 커버리지 진행 가시성을 보강했다. `web/index.html` 의 `최근 검증된 작업` 표에 `충돌/타일 클래스 커버리지` 행을 추가해 `collision_review.html` 로 바로 들어가게 했고, `web/progress.html#evidenceHandoffPanel` 에 `collision-tile-class-coverage` local evidence row 를 추가했다. 이 행은 collision review 의 174개 맵 coverage, 평균 97.77%, full coverage map 59개, map tile class gap 1090행을 보여주되 strict source hotspot/route collision proof 가 없으므로 route promotion 충돌 증거로 승격하지 않는다고 명시한다. `HWANSE_LAST_HOME_RENDER` 는 `recentWorkRowCount=11`, `recentWorkCollisionCoverageHref=collision_review.html` 을 남기고, `HWANSE_LAST_PROGRESS_RENDER` 는 `progressEvidenceHandoffRowCount=22`, `progressEvidenceHandoffLocalRowCount=18`, `progressEvidenceHandoffCollisionTileCoverageIncluded=True`, `progressEvidenceHandoffCollisionTileCoverageHref=collision_review.html` 을 남긴다. 이는 1차 목표인 통행 가능 영역/충돌/우선순위 추정 진행을 일반 관리 홈에서 바로 확인하게 하는 관리자 UX/진행 가시성 보강이며, strict hotspot coordinate, selected-root/runtime proof, real selector `2:0` savedata, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 관리 홈/진행 화면의 WLK/MLK 복원 링크를 보강했다. `web/index.html` 의 `최근 검증된 작업` 표에 `WLK/MLK 복원 확정` 행을 추가해 `audio_review.html` 로 들어가게 했고, `web/progress.html#evidenceHandoffPanel` 에 audio archive restoration local evidence row 를 추가했다. 이 행은 WLK embedded title `0`, browser cue label `9`, EXE id label `45`, MLK embedded `16`, fallback `4`, WLK 54개/MLK 20개 manifest 검증과 MLK soundfont smoke 를 표시하되 original DirectSound/WinMM playback parity 로 승격하지 않는다고 명시한다. 이후 충돌/타일 클래스/VM opcode 행까지 포함해 `HWANSE_LAST_HOME_RENDER` 는 `recentWorkRowCount=11`, `recentWorkAudioTitleHref=audio_review.html` 를 남기고, `HWANSE_LAST_PROGRESS_RENDER` 는 `progressEvidenceHandoffRowCount=22`, `progressEvidenceHandoffLocalRowCount=18`, audio archive restoration link 를 남긴다. 이는 제목 없는 WLK/MLK 상태와 EXE id 번호 체계를 관리 홈에서 놓치지 않게 하는 관리자 UX/진행 가시성 보강이며, original audio playback parity, DirectSound mixer/timing, WinMM MIDI runtime 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 전체 맵 검토 화면의 소스/조립 커버리지 표를 보강했다. `web/map_gallery.html` 에 `맵 소스/조립 커버리지` 6행 표를 추가해 field map CNS source index 174/174, accepted assembled map renders 174/174, 기본 accepted scope 의 single-map source/assembly review links 174, source CNS links 174, browser overview links 174, route promotion proof 0/blocked 를 분리해서 보여준다. `web/index.html` 의 `최근 검증된 작업` 은 이후 오디오/충돌/VM opcode 행까지 포함해 11행이 되었고, `web/progress.html#evidenceHandoffPanel` 은 이후 `audio-archive-restoration`, `collision-tile-class-coverage`, `format-vm-opcode-coverage` local evidence row 까지 포함해 22행 handoff, local 18 / external 4 로 갱신했다. `HWANSE_LAST_MAP_GALLERY_RENDER` 는 `browserMapSourceCoverageTableImplemented=True`, `mapSourceCoverageRowCount=6`, `mapSourceCoverageGlobalMapCount=174`, `mapSourceCoverageAcceptedMapCount=174`, `mapSourceCoverageVisibleSourceLinkCount=174`, `mapSourceCoverageVisibleReviewLinkCount=174`, `mapSourceCoverageRoutePromotionBlocked=True`, `mapSourceCoverageNonPromoting=True` 를 남긴다. `HWANSE_LAST_HOME_RENDER` 는 `recentWorkRowCount=11`, `recentWorkMapSourceCoverageHref=map_gallery.html` 을 남기고, `HWANSE_LAST_PROGRESS_RENDER` 는 `progressEvidenceHandoffRowCount=22`, `progressEvidenceHandoffLocalRowCount=18`, `progressEvidenceHandoffMapSourceCoverageIncluded=True`, `progressEvidenceHandoffMapSourceCoverageHref=map_gallery.html` 을 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` smoke 요약은 `mapSourceCoverage=6/174` 를 남긴다. 이는 사용자가 전체 맵 소스와 조립 완료 맵을 `legacy aggregate asset workbench (removed)` 에서 뒤지지 않고 관리 맵 갤러리에서 한눈에 보게 하기 위한 관리자 UX/진행 가시성 보강이며, strict hotspot coordinate, selector `2:0` captured savedata, selected-root runtime execution, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 몬스터 검토 화면의 추출 범위 표를 보강했다. `web/monster_review.html` 에 `몬스터 추출 범위` 5행 표를 추가해 전체 추출 enemy/object sprite 65개, enemy 58개, object 7개, source-linked battle candidates 8 unique/21 rows, promoted original enemy rows 0 을 분리해서 보여준다. 표는 전체 추출 범위 `monster_review.html?scope=all` 과 source-linked 후보 범위 `monster_review.html?scope=candidate` 직접 링크도 제공한다. 홈 최근 검증 작업의 몬스터 행도 같은 전체/후보 scope 링크를 노출한다. `HWANSE_LAST_MONSTER_REVIEW_RENDER` 는 `browserMonsterExtractionCoverageImplemented=True`, `monsterCoverageRowCount=5`, `monsterCoverageExtractedSpriteCount=65`, `monsterCoverageEnemySpriteCount=58`, `monsterCoverageObjectSpriteCount=7`, `monsterCoverageSourceLinkedSpriteCount=8`, `monsterCoverageBattleCandidateRowCount=21`, `monsterCoverageScopeLinkCount=2`, `monsterCoverageAllScopeHref="monster_review.html?scope=all"`, `monsterCoverageCandidateScopeHref="monster_review.html?scope=candidate"`, `monsterCoverageDefaultScopeAllSprites=True`, `monsterCoverageOriginalEnemyRowsBound=False`, `monsterCoverageNonPromoting=True` 를 남기고, `HWANSE_LAST_HOME_RENDER` 는 `recentWorkMonsterScopeAllHref="monster_review.html?scope=all"`, `recentWorkMonsterScopeCandidateHref="monster_review.html?scope=candidate"` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` smoke 요약은 `monsterCoverage=65/8` 을 남긴다. 이는 사용자가 몬스터가 적게 보인다고 느낄 수 있는 후보 8개 subset 과 전체 추출 갤러리 65개를 같은 화면에서 분리하기 위한 관리자 UX 보강이며, original enemy row/stat/formation/reward/formula, original attack sequence/AI, event-driven battle entry 또는 route promotion proof 로 승격하지 않는다.
- 2026-06-11 시스템/세이브 검토 화면의 save/equipment/status offset 경계를 보강했다. `web/system_review.html` 에 `세이브 장비/상태 오프셋 경계` 6행 표를 추가해 known editor save fields, selector `2:0` route-critical gap, equipment ownership offsets, prototype equipment effect runtime, status flag offsets, story/event flag runtime 을 한곳에서 분리한다. 8013 기준 `tools/verify_home_landing_browser.py` smoke 는 `systemOffsetBoundary=6` 을 남기고, `HWANSE_LAST_SYSTEM_REVIEW_RENDER` 는 `browserSystemOffsetBoundaryTableImplemented=True`, `systemOffsetBoundaryRowCount=6`, `systemOffsetBoundaryGroundedRowCount=1`, `systemOffsetBoundaryPassedRowCount=1`, `systemOffsetBoundaryPartialRowCount=1`, `systemOffsetBoundaryMissingRowCount=3`, `systemOffsetBoundaryKnownSemanticByteCount=160`, `systemOffsetBoundaryUnknownVaryingRangeCount=87`, `systemOffsetBoundaryEquipmentEvidenceStatus="offsets-unmapped"`, `systemOffsetBoundaryNonPromoting=True` 를 남긴다. 이는 후보 장비/상태 UI가 통과했더라도 original ownership/equipped-slot offsets, poison/paralysis/fallen status flag offsets, story/event flag writers, selector `2:0` captured savedata 가 미확보임을 관리 화면에서 읽기 쉽게 하는 보강이며, original save system parity, equipment/status/story runtime proof, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 관리 홈의 자산 분리 현황 표를 보강했다. `web/index.html` 에 일반 관리 표 형태의 `자산 분리 현황` 섹션을 추가해 `legacy aggregate asset workbench (removed)` 을 다시 뒤지지 않아도 맵 소스 파일(`../extract_fld/map1_02b.cns`), 조립 완료 맵 검토(`map_review.html?map=map1_02b&visualFilter=layer1UnderSceneTilesets&tileIndexFilter=row40_zero`), 몬스터 이미지 소스(`monster_review.html?asset=zk_big`), 몬스터 공격 프레임(`monster_review.html?asset=zk_big&attack=special-or-reaction`), 전투 수치/공식 근거(`../out/original_battle_numeric_context.html`), 음원 제목 출처(`../out/audio_title_provenance.html`)를 6행으로 바로 열 수 있게 했다. `HWANSE_LAST_HOME_RENDER` 는 `browserHomeAssetSplitStatusImplemented=True`, `browserHomeAssetSplitAdminTable=True`, `browserHomeAssetSplitLinksImplemented=True`, `assetSplitRowCount=6`, 각 `assetSplit*Href` marker 를 남기고, 8013 기준 `tools/verify_home_landing_browser.py` smoke 는 `assetSplitRows=6` 을 콘솔/`out/home_landing_browser_smoke.*` 에 기록한다. 이는 메인 랜딩을 게임형이 아닌 일반 웹 관리뷰로 유지하면서 맵 소스-vs-완성형, 몬스터 소스-vs-공격 프레임, 전투 수치 gap, 음원 제목 provenance 를 첫 화면에서 찾기 쉽게 하는 UX/진행 가시성 보강이며, original route execution, enemy AI, combat formula, playback parity 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 몬스터/전투 검토 화면의 왕복 링크와 전투 수치/공식 경계를 보강했다. `web/battle_analysis.html?candidate=event-dialogue-block-015%3Abtl_b1` 에서 `monster_review.html?asset=zky_ao&attack=primary-command` 로 넘어가던 전투 후보 -> 몬스터 검토 링크에 이어, `web/monster_review.html` 도 소스 전투 후보가 연결된 몬스터에서 `battle_analysis.html?candidate=...` 로 되돌아가는 링크를 제공한다. 기본 선택 몬스터 `boss_2` 는 `event-dialogue-block-041:btl_a1` 후보 검토로 연결되고, 후보 표에는 source-backed candidate 2개 링크가 뜨며, 전체 공격 후보 매트릭스에는 기존 65개 전투 실행 링크를 유지한 채 source-linked monster 8개에 대한 battle review link 8개가 별도로 추가된다. `web/battle_analysis.html` 에는 `원본 전투 수치/공식 경계` 6행 표도 추가해 descriptor context 123개, candidate pair 21개, close pair 9개, numeric run 32개, local run pair 16개, close local run pair 8개를 보여주되 promotion blocker 를 `descriptor-context-only-no-handler-row-stride-or-runtime-edge` 로 고정하고 enemy/reward row 및 combat formula proof 는 missing 으로 둔다. 이후 관리 홈의 `최근 검증된 작업` 표는 오디오/충돌/VM opcode 행까지 포함해 11행이 되었고, `progress.html#evidenceHandoffPanel` 은 `monster-battle-review-backlinks`, `battle-numeric-formula-boundary`, `system-offset-boundary`, `map-source-assembly-coverage`, `audio-archive-restoration`, `collision-tile-class-coverage`, `format-vm-opcode-coverage` local evidence row 를 포함해 22행 handoff, local 18 / external 4 로 갱신했다. `HWANSE_LAST_MONSTER_REVIEW_RENDER` 는 `browserMonsterBattleReviewLinksImplemented=True`, `selectedBattleReviewHref=battle_analysis.html?candidate=event-dialogue-block-041%3Abtl_a1`, `candidateBattleReviewLinkCount=2`, `attackOverviewBattleReviewLinkCount=8` 을 남기고, `HWANSE_LAST_BATTLE_REVIEW_RENDER` 는 `browserBattleNumericBoundaryTableImplemented=True`, `battleNumericBoundaryRowCount=6`, `battleNumericBoundaryGroundedRowCount=1`, `battleNumericBoundaryCandidateRowCount=2`, `battleNumericBoundaryBlockedRowCount=1`, `battleNumericBoundaryMissingRowCount=2`, `battleNumericBoundaryNonPromoting=True` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` smoke 는 `monsterBattleReviewLinks=8`, battle numeric boundary `6 rows`, 홈 recent work `11 rows`, progress handoff `22 rows / local 18` 로 확인한다. 이는 관리자 검토 화면 사이의 추적성과 원본 전투 수치/공식 gap 가시성을 높이는 작업이며, 원본 enemy row, original attack sequence, enemy AI, combat formula, event-driven battle entry, route promotion proof 로 승격하지 않는다.
- 2026-06-10 관리자 웹은 게임 화면이 아니라 일반 검토/관리용 웹 뷰로 분리했다. `/web/index.html` 은 통합 랜딩으로 두고, 실제 게임 화면은 `game.html?game=1` 메뉴로 옮겼으며, `game.html?game=1`/`game.html?play=1`/`game.html?savedatScan=1` 링크는 리뷰 목록이나 상단 요약이 아니라 하단 `보조 검증 도구` 표에만 둔다. `web/game.html` 안에 남아 있던 예전 홈 섹션은 `data-deprecated-game-landing="true"`/`hidden` 으로 내리고, 쿼리 없는 `game.html` 은 `index.html` 로 보내며 기본 scene 도 더 이상 `"home"` 으로 떨어지지 않게 했다. 테스트 웹 포트는 8013 기준으로 고정했다. `web/savedata_review.html` 은 `SAVEDATA/`/`SaveData/` captured savedat 투입 위치, `savedatScan=1` 브라우저 확인 링크, refresh/scan 명령을 세이브 intake 테이블로 직접 노출한다. `web/menu_review.html` 은 후보 상점 품목 6개를 구매/판매 prototype 가격, runtime count, EXE item text ref 별 상세 표로 노출하고, 동료 후보 2명도 메뉴 합류/대사 합류/팔로워 표시 별 상세 표로 노출한다. 후보 기술 6개는 캐릭터/individual-group/Lv/MP/value/EXE text ref 별 상세 표로, 후보 장비 18개는 대상/슬롯/스탯/EXE text ref 별 상세 표로, 상태 후보 4개는 savedata/prototype 출처와 Lv/HP/MP/스탯/기술 수 별 상세 표로 노출해 상점/동료/기술/장비/상태 prototype 과 original shop/party/skill/equipment/status gap 을 같이 확인하게 했다. 이는 `map1_01a -> map2_02d` route promotion 을 승격하지 않고, 외부 세이브/trace/hotspot 증거가 들어왔을 때 어디서 확인할지와 브라우저-local 메뉴 구현 범위를 분명히 하기 위한 진행 관리 보강이다.
- 2026-06-10 관리 홈 런타임 실행 링크 표 보강: `/web/index.html` 의 일반 관리 홈 안에 `런타임 실행 링크` 표를 보조 관리 표로 추가해 타이틀 메뉴, 필드 이동, 대사 후보, 전투 후보, `zk_big` 스프라이트 전투, 세이브 후보, 오브젝트 조사 후보, 상점 후보, 동료 후보, 기술 메뉴, 장비 메뉴, 상태 메뉴, 진행 기록, 스토리 상태, 확정 전환, `routeAssist` 후보 루트를 16개 direct runtime link 로 바로 열 수 있게 했다. 스프라이트 전투 행은 `game.html?map=map2_14j&battle=1&battleCandidate=sprite-only%3Azk_big` 로 추출 enemy/object sprite-only 전투를 직접 열어 공격 애니메이션 프레임을 확인하게 하고, 세이브 후보 행은 `game.html?map=map2_07e&startTile=11%2C11&menu=save-point` 를 써서 맵만 여는 것이 아니라 후보 선택 메뉴까지 직접 연다. 오브젝트/상점/동료/기술/상태/진행/스토리 행도 `menu=object|shop|party|skill|status|progress|story` 직접 런타임 링크를 쓴다. 확정 전환 행은 `game.html?map=map1_02b&startTile=11%2C12&transitionTarget=map1_01a` 로 confirmed `map1_02b -> map1_01a` prompt/fade/save 경로에 바로 들어간다. 각 행은 대응 smoke artifact(`title_start`, `candidate_movement`, `candidate_dialogue_progress`, `candidate_battle`, `candidate_save_point`, `candidate_event_object`, `candidate_shop_menu`, `candidate_party_join`, `candidate_skill_menu`, `candidate_equipment_menu`, `candidate_status_menu`, `candidate_progress`, `candidate_transition_progress`, `route_guide`)와 `browser verified`/`partial`/`prototype`/`browser-local`/`trial only` 범위를 함께 보여준다. `HWANSE_LAST_HOME_RENDER` 는 `browserHomePlayableSlicesImplemented=True`, `browserHomeRuntimeLinksPresentedAsAdminIndex=True`, `playSliceRowCount=16`, 각 href marker, `browserHomePlayableSlicesNonPromoting=True` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py`/`tools/verify_runtime_http.py` 가 8013 기준 DOM과 static marker 를 검증한다. 이는 사용자가 현재 체감 가능한 웹 포팅 조각을 일반 관리 웹뷰에서 확인하기 위한 UX/실행 보강이며, original event VM execution, original enemy row/formula/reward proof, original save-point runtime, original object/shop/party/skill/equipment/status/story runtime, strict hotspot, route promotion proof 를 대체하지 않는다.
- `tools/decode_cns.py` 추가. `cns110.exe` 의 LZ 계열 스트림을 재구현.
- `docs/CNS_FORMAT.md` 추가.
- UI 파일, `title.cns`, `face_01.cns`, `map_a1.cns` 를 PNG 로 디코드 확인.
- `tools/classify_cns_payloads.py` 기준 전체 377개 CNS 중 177개는 이미지, 200개는 타일맵으로 분류. 필드 맵은 `map[0-9]*.cns` 174개, 전투 배경 `btl_*` 타일맵은 26개다.
- `out/event_dialogue_blocks_runtime.js` 는 opcode `0x02`/`0x0d`/`0x0b`/`0x35` 주변 CP949 대사 후보와 partial opcode replay trace 를 웹에서 늦게 로드하는 축약 데이터로 내보내며, 526개 `0x02` cursor/separator trace, 41개 블록의 `0x35` literal payload 249개, 47개 블록의 grounded control/display metadata 1007개를 보존한다. control/display metadata 는 `browserExecutesEffect=False` 로 남겨 원본 VM effect 실행으로 승격하지 않는다. 현재 맵 파일명에 직접 연결된 후보는 게임 화면에서 Enter/모바일 A 또는 상단 `대사` 버튼으로 바로 대화창을 열 수 있고, `dialogue=1`/`D` 키/메뉴 `대사 후보` 는 같은 타일셋 계열의 넓은 후보까지 재생한다. WebKit smoke 는 `map4_08n` 에서 `dialogueButton` 을 클릭해 `event-dialogue-block-005` 를 열고 `vmPartial=True`, `vmFull=False`, `vmOpcodes` 에 `0x02`/`0x0d`/`0x0b` trace 를 남기며, `vmDriven=2/13`, `vmCoverage=partial-render-prefix`, `vmSource=0x00030000` 를 확인한 뒤 모바일 A 로 다음 줄을 넘기는 경로를 확인한다. 아직 route-linked event 실행 증명이나 full event VM 구현 완료는 아니다.
- 2026-06-06 대사 per-render VM state 보강: 브라우저 partial event VM replay 는 grounded control/display metadata 를 최종 상태로만 보지 않고 VA 순서대로 적용해 각 opcode `0x0b` render event 에 `controlTextLayout`, `displayStyleRender`, `dataBank`, 적용 control count 를 붙인다. `drawDialogueBox()` 는 현재 줄의 render-state snapshot 을 우선 사용하며, `tools/verify_candidate_dialogue_progress_browser.py` 는 `event-dialogue-block-005` 에서 `renderStateSnapshots=2`, 첫 render `0x0045ee54`, `origin=16,16`, `style=default`, `dataBank=0`, `appliedControls=6`, `browserEventVmRenderStateSnapshotImplemented=True` 를 검증한다. 이는 EXE-derived opcode metadata 의 시점별 브라우저 적용 증거이지만 branch target 실행, route-linked event VM execution, full event VM, story flag proof 는 계속 false 다.
- 2026-06-07 대사 event VM branch 실행 trace 보강: `eventVmKnownBranchExecution()` 은 추출된 known instruction row 안에서 handler-grounded `0x09` call target/continuation 과 `0x0a` return stack 을 bounded executor 로 따라간다. 기존 VA 순서 control-flow 요약(`controlFlow=4/1`, `maxDepth=4`)은 유지하되, 실제 jump/return 순서 trace 를 별도 `groundedControlBranchExecution` 으로 남긴다. `drawDialogueBox()` 는 branch executor 가 해당 line index 의 render event 를 만들었으면 기존 sequential partial replay 보다 이 branch render event 를 우선 사용하고, render event 가 없는 줄은 opcode `0x02` separator 기반 `lineAdvanceEvents` 를 사용한다. opcode `0x06` wait 도 branch 실행 중 현재 line index 와 묶어 `waitEvents` 와 latch snapshot 에 남긴다. `0x35` CP949 literal payload 는 fallback line 과 일치할 때 대화 박스의 직접 `lineSource=literal-cp949-text-payload` 로 승격한다. 8013 기준 `tools/verify_candidate_dialogue_progress_browser.py` 는 `event-dialogue-block-005` 에서 `branchExecSteps=62`, `branchExecRenders=6`, `branchExecLineAdvances=8`, `branchExecWaits=4`, `branchExecReturns=5`, `branchExecMaxDepth=1`, `branchExecFinalDepth=0`, `branchExecHalt=end-of-known-instructions`, `branchExecFirstTarget=0x0045ee2c`, `branchExecFirstContinuation=0x0045ee64`, `browserEventVmBranchExecutionImplemented=True` 를 검증하고, canvas pointer 로 0->1 진행한 실제 렌더 snapshot 이 `branchRender=branch-execution:0x0045ee54:17:1`, `branchRenderSelection=True` 로 두 번째 줄 `이곳은 주작의 시련이 있는 곳` 을 branch 실행 render 로 선택하는지도 확인한다. 또한 separator-only 줄 probe 는 `branchLineAdvance=branch-line-advance:6:0x0045ef2c:5`, `branchLineAdvanceSelection=True` 로 7번째 줄 `주작권사` 의 대화 박스 상태를 branch line-advance 이벤트에서 가져오고, wait probe 는 `branchWait=0x0045eeb4:3:1`, `branchWaitLatch=True`, `branchWaitChrome=True` 로 4번째 줄 `주작권사` 의 input-release wait 근거를 branch wait 이벤트에서 가져오는지 확인한다. literal payload probe 는 `event-dialogue-block-001` 에서 `literalEvents=7`, `branchLiteralExec=7`, `branchLiteralMatched=10`, `firstRender=branch-execution:literal-cp949-text-payload:0x00441737:다리오스`, `lineAdvance=branch-execution:literal-cp949-text-payload:0x00441754:도대체 어디 있는거니`, `browserEventVmLiteralTextPayloadLineImplemented=True` 를 검증한다. 이는 이미 해제/추출된 opcode metadata 안에서 branch stack 실행 순서를 더 실제 VM에 가깝게 재생하고 화면 렌더/입력 wait/문자열 payload 근거에도 반영하는 웹 구현 보강이지만, route-linked event dispatch, full instruction set, story flag mutation proof 로 승격하지 않는다.
- 2026-06-07 branch 실행 trace 에 display/cursor/control opcode 근거를 추가했다. `eventVmKnownBranchExecution()` 은 opcode `0x03` font row, `0x04` display timer, `0x07` fixed object position, `0x08` display style, `0x0e` cursor relative, `0x15` text origin, `0x1b` data bank, `0x37` global timer 를 실제 branch 실행 순서의 event 배열로 기록하고 line index, line text, branch step, stack depth, 이전 render VA, operand/layout/style/object/data snapshot 을 남긴다. 8013 기준 browser smoke 는 `event-dialogue-block-005` 에서 `branchTextOrigin=5:0x0045ee44:16,16`, `branchGlobalTimer=5:0x0045ee4c:0` 를 확인하고, `event-dialogue-block-029` 에서 branch 반복 실행 visit 을 반영한 `branchFontRow=12:0x004ec78a:2`, `branchDisplayStyle=12:0x004ec78e:1:emphasis`, `branchObjectPosition=12:0x004ec79a:144,248`, `branchDisplayTimer=12:0x004ec7a2:2880` 을 확인하며, `event-dialogue-block-028` 에서 `branchCursorRelative=37:0x004e8054:24,96`, `branchDisplayTimer=5:0x004e7ffc:1856`, `branchStyle=6:0x004e7ff0:0`, `branchObject=5:0x004e8000:0,352`, `branchDataBank=4:0x004e8088:0` 을 확인한다. 이는 이미 해제한 handler-grounded control opcode 의 브라우저 실행 순서 증거를 강화하는 작업이며, 여전히 full event VM/runtime story flag 구현 완료로 승격하지 않는다.
- 2026-06-09 대사 완료 story-state 표면 보강: 브라우저 런타임은 `prototypeProgress` 의 `dialogue-complete`/`object-inspect`/`battle-victory`/`party-join-prototype`/`route-*` 이벤트에서 browser-local `prototypeStoryFlags` 를 파생해 runtime save payload 에 저장하고 `window.HWANSE_LAST_PROTOTYPE_STORY_FLAGS` 로 노출한다. 8013 기준 `tools/verify_candidate_dialogue_progress_browser.py` 는 `map4_08n` 에서 `event-dialogue-block-005` 완료 후 `storyFlags=1`, `savedStoryFlags=1`, key `story:dialogue-complete:map4_08n:event-dialogue-block-005` 를 확인하고, `event-dialogue-block-026` 까지 완료한 뒤 `storyFlags=2`, key `...block-005,...block-026` 이 title `이어하기 map4_08n 11,11` 복원 후에도 남는지 검증한다. `tools/verify_candidate_battle_browser.py` 는 `map1_02b` 대사 전투 완료 저장/복원에서 key `story:battle-victory:map1_02b:event-dialogue-block-015` 를 확인하고, 승리 auto-save marker 도 같은 `storyFlagKeys`/`storyFlagCounts` 를 노출하는지 검증한다. `tools/verify_candidate_route_progress_browser.py` 는 `map2_14j` 완료/클리어 게이트와 title 복원 경로에서 key `story:route-complete:map2_14j:route-complete:map2_14j`, `story:route-clear:map2_14j:route-clear:map2_14j` 를 확인한다. 이는 진행 저장/복원을 위한 브라우저-local story-state 표면이며 `browserPrototypeStoryFlagImplemented=True` 로만 기록하고, 원본 story flag offset/runtime mutation proof 는 `originalStoryFlagRuntimeImplemented=False` 로 유지한다.
- `out/event_vm_opcode_semantics.html` 은 event/object VM dispatch table `0x0047f1d8` 근거로 opcode `0x02` cursor/separator, control/display opcode `0x03`/`0x04`/`0x06`/`0x07`/`0x08`/`0x09`/`0x0a`/`0x0e`/`0x15`/`0x1b`/`0x37`, 텍스트 관련 opcode `0x0b`/`0x0c`/`0x0d` 의 length/operand/effect 를 따로 고정한다. `0x02` 는 4바이트 cursor/separator, `0x03`/`0x04`/`0x06`/`0x1b`/`0x37` 은 4바이트 display/wait/state, `0x07`/`0x09`/`0x0e`/`0x15` 는 8바이트 position/control-flow/cursor opcode, `0x08` 은 mode0 4바이트/mode1 8바이트 style opcode, `0x0a` 는 continuation stack return 으로 기록하지만, route-linked `0x0c` hit 는 pointer overlap 이라 승격하지 않는다. `out/event_vm_semantics_gap.html` 은 save-selector script handler table `0x00440720` 의 first-byte 후보 35개, event/object handler table `0x0047f1d8` 의 64개 dispatch entry, opcode `0x02` cursor/separator handler, opcode `0x03`/`0x04`/`0x06`/`0x07`/`0x08`/`0x09`/`0x0a`/`0x0e`/`0x15`/`0x1b`/`0x37` control/display handlers, opcode `0x0b` text routine handler, opcode `0x0d` text-source command, 47개 dialogue storage block 을 통합한다. 상태는 `handler-storage-grounded-execution-missing` 으로 고정하며, 브라우저 런타임은 indexed dialogue block 의 partial `0x02`/`0x0d`/`0x0b`/`0x35` replay trace 와 1007개 grounded control/display metadata 를 보존한다. `out/candidate_dialogue_progress_browser_smoke.*` 는 이 중 bounded branch/control replay 가 실제 대사 render/style/cursor/object/input-wait snapshot 에 반영되는지 확인해 `browserGroundedControlReplayImplemented=True`, `branchExecution=62/6`, `renderStateSnapshots=2`, `cursorRelative=37/20`, `literalPayload=7/7/10` 을 남긴다. text-source opcode, `0x02`, 일부 control/display opcode instruction length/effect 는 grounded 되었지만, 전체 VM instruction length/operand layout, route-linked event VM execution, full browser event VM implementation, story dialogue route proof 는 false 로 남긴다.
- `out/save_point_candidates.html` 은 원본 저장이 여관/석상/회복 NPC 같은 event save point 에서만 가능했다는 플레이어 기억을 기준으로 event dialogue/text 후보를 다시 분류한다. `out/save_point_candidates_runtime.js` 는 같은 후보를 웹 메뉴의 `세이브 후보` 읽기 전용 검토 대화로 제공한다. 현재 `데이터 저장`/`데이터 로드` 는 system/menu 텍스트로 분리되고, 여관 문맥은 3개 대사 블록에서만 후보로 잡힌다. exact `석상`/`신상` 텍스트와 proven HP 회복 NPC save event 는 아직 없으므로, 원본 save point 이벤트는 미구현이고 웹의 `임시 저장`/`임시 불러오기` 는 debug 상태 보존으로만 남긴다.
- `out/battle_backgrounds.js`/`.json` 는 26개 `btl_*` 전투 배경 타일맵을 런타임용으로 내보낸다. `out/battle_event_candidates.js`/`.json` 는 `btl_*` 리소스와 주변 event dialogue block 이 같이 잡힌 21개 후보를 묶어, 현재 맵 타일셋 계열에 맞는 전투 배경/대사 후보를 고르게 한다. `out/event_battle_gap_audit.html` 은 WebKit smoke 로 확인된 candidate 대화/전투/아이템 prototype 범위와 원본 event VM, event-driven 전투 진입, 적 데이터/공식/보상, 장비/상태/story flag gap 을 분리해 completion audit 이 이 항목을 partial 로 유지하게 한다. 이 audit 은 opcode `0x0b` 텍스트 렌더 핸들러와 opcode `0x0d` context+0x28 source command 는 grounded 로 두되, route-linked command hit 2개가 pointer overlap 이고 scene event direct text ref 가 0개라 story dialogue route proof 로 승격하지 않는다. 웹 런타임은 메뉴/상단의 `전투` 버튼 또는 `/web/game.html?map=map1_02b&battle=1` 로 전투 검토 장면을 열고, 전투 배경/전투 캐릭터 스프라이트/추출된 전투 명령 텍스트/후보 대사 로그를 사용해 키보드와 모바일 A/조이스틱으로 명령을 눌러볼 수 있다. `전투 선택` 메뉴는 현재 맵에 맞는 이벤트 기반 후보와 추출된 `boss_*`/`z*` 적/오브젝트 스프라이트 65개를 분리해 보여주며, 65개 스프라이트는 generated prototype profile 로 전투 장면에 직접 띄울 수 있다. 동료가 있으면 전투 파티에 반영되고 행동 턴도 생존 동료 사이에서 순환하며, 기본 공격명은 추출된 캐릭터별 액션 텍스트 테이블을 따른다. savedat 의 learned skill count 는 decoded slot/index/level entry 를 보존한 뒤 추출된 스킬/액션 텍스트 테이블 기반 전투 커맨드를 추가하고, WebKit smoke 는 Ataho 의 `돌려차기`가 MP 를 소비하며 적 HP 를 줄이고 savedat-backed MP row 에 동기화되는지, MP 부족 시 적 HP/source row/턴을 바꾸지 않고 거부되는지, Rinshan/Smashu 의 learned skill commands 및 Rinshan `장궁`/Smashu `투구쪼개기` 실행도 확인한다. savedat 아이템은 맵 메뉴와 전투 도구 명령에 반영되어 약초를 소비해 HP 를 회복할 수 있고, 해독초는 웹 런타임의 독/마비 상태 모델을 치료하며, revive 플래그가 있는 아이템만 쓰러진 동료를 대상으로 삼는다. 맵 메뉴에서 바뀐 HP/아이템 수량/상태와 savedat selector 맵 후보는 debug용 `임시 저장`/`임시 불러오기` 로 보존된다. 원본 저장은 아무 필드 메뉴에서나 되는 것이 아니라 여관/석상/회복 NPC 같은 event save point 에 묶인 것으로 기록하며, 원본 save point 이벤트는 아직 구현하지 않았다. savedat 이 없는 수동 동료 선택도 임시 저장/불러오기로 복원된다. WebKit smoke 는 `battleButton` 으로 manual party 전투를 시작해 Ataho/Rinshan/Smashu 턴 진행과 보상을 확인하고, public savedat 전투/메뉴에서 약초, 마법의 물약, 해독초, 마수석 사용을 확인한다. 마수석은 쓰러진 Smashu 를 full HP/MP 로 되살리고 savedat-backed source row 에 동기화되는지 검증한다. 승리 시 후보 전투 보상 소지금/EXP도 지급하고, 종료된 전투는 A 버튼으로 맵에 복귀하며 임시 저장/불러오기로 보상 소지금/EXP와 수동 동료 선택을 함께 보존한다. 아직 원본 event-driven 전투 진입, 적 데이터, 전투 공식, 원본 상태 플래그 offset, 원본 save point 이벤트, 보상/스토리 플래그는 구현하지 않았다.
- `out/original_battle_resource_descriptors.html` 은 EXE 안의 battle/background/enemy CNS resource-load descriptor 를 따로 고정한다. 현재 `btl_*` 전투 배경 descriptor ref 44개(25/26 payload, missing `btl_o2.cns`), `z*`/`boss_*` 적/오브젝트 sprite descriptor ref 65개(64/65 payload, missing `zky_nmk.cns`), `btl_*` 전투 sprite descriptor ref 14개가 확인됐고, `out/original_battle_data_gap.html` 은 이 값을 상위 전투 데이터 gap 에 반영한다. 웹 asset table 과 `legacy aggregate asset workbench (removed)` 은 65개 적/오브젝트 스프라이트를 모두 PNG/runtime asset 으로 노출하며, 전투 선택 메뉴는 이 65개를 sprite-only prototype 전투 후보로 선택 가능하게 한다. 추가로 `out/original_battle_numeric_context.html` 은 123개 battle-related descriptor context 와 21개 battle/enemy 후보 pair 를 스캔해 descriptor-local numeric run 32개, local run 을 가진 후보 pair 16개, close-resource local-run pair 8개를 보존한다. 이 숫자들은 모두 `descriptor-context-only-no-handler-row-stride-or-runtime-edge` 로 막혀 있으며, 리소스 로드 row/숫자 run 근거이지 enemy row, formation/encounter table, reward table, combat formula, battle-entry event execution 이 아니므로 완료 승격하지 않는다.
- 2026-06-04 전투 도구 사용 자동 저장 보강: `useBattleItem()` 의 성공한 전투 도구 효과는 이제 `source=prototype-battle-item-effect` 로 `item-use-prototype` 진행을 기록하고, 내부 autosave 에 한해 active battle 저장을 허용하는 `allowBattle` 경로로 `scope=battle-item` payload 를 남긴다. `tools/verify_mobile_browser_controls.py` 는 public savedat 전투에서 약초와 마법의 물약 메뉴 사용이 각각 `itemAutoSource=item-use-prototype`/`menuAutoSource=item-use-prototype` 를 만들고, 저장 payload 에 HP/MP 및 아이템 수량 변화를 보존하는지 확인한다. 이는 웹 프로토타입의 전투 도구 상태 보존이며 원본 아이템 공식, 원본 상태 플래그, story flag 구현 증거는 아니다.
- 2026-06-04 전투 기술 사용 자동 저장 보강: `useSelectedBattleCommand()` 의 성공한 skill command 는 이제 `source=prototype-battle-skill-effect` 로 `battle-skill-prototype` 진행을 기록하고, 내부 active battle autosave 로 `scope=battle-skill` payload 를 남긴다. `tools/verify_mobile_browser_controls.py` 는 public savedat 전투에서 Ataho `돌려차기`가 MP 를 소비하고 적 HP 를 줄인 뒤 `skillAutoSource=battle-skill-prototype` 를 만들며, 저장 payload 에 MP/적 HP 진행 기록과 savedat-backed MP row 를 보존하는지 확인한다. MP 부족 가드는 계속 적 HP, source row, 턴을 바꾸지 않는다. 이는 웹 프로토타입의 전투 기술 상태 보존이며 원본 기술 공식, 전투 공식, story flag 구현 증거는 아니다.
- 2026-06-04 전투 턴 결과 자동 저장 보강: 플레이어 명령 뒤 적 반격이 실제로 들어간 턴은 이제 `source=prototype-battle-turn-result` 로 `battle-turn-prototype` 진행을 기록하고, `scope=battle-turn` payload 에 명령명, 방어 여부, 적 행동명, 대상 HP/status 전후와 damage 를 남긴다. `tools/verify_mobile_browser_controls.py` 는 manual party 전투의 일반 공격 `정권` 후 `normalTurnAutoSource=battle-turn-prototype` 가 생성되어 Ataho 의 반격 후 HP 를 저장하는지 확인하고, public savedat 전투에서는 `돌려차기` 후 `turnAutoSource=battle-turn-prototype` 가 생성되며 약초/마법의 물약 사용 뒤에도 latest 저장 payload 가 적 반격 후 HP/status 및 진행 기록을 보존하는지 확인한다. 이는 웹 프로토타입 턴 상태 보존이며 원본 적 AI, 상태 공식, 전투 공식, story flag 구현 증거는 아니다.
- 2026-06-04 전투 상태이상 저장/이어하기 보강: `tools/verify_candidate_battle_browser.py` 는 `map2_07e` 의 `event-dialogue-block-038:btl_n2` 전투에서 적 `철갑 코뿔` 의 `독액` 반격이 Ataho 에 `poison` 상태를 붙이고, `battle-turn-prototype` 자동 저장 payload 가 해당 상태와 진행 카운트를 보존하는지 확인한다. 이후 타이틀 `이어하기 map2_07e 11,11` 로 복귀해 상태 메뉴 `status-menu:map2_07e` 에 `상태 독` 이 다시 표시되는지도 확인한다. 이는 웹 프로토타입의 상태이상 저장/복원 루프 보강이며 원본 상태 플래그 offset, 적 AI, 상태 공식, story flag 구현 증거는 아니다.
- 2026-06-05 전투 시작 overlay 보강: `startBattlePrototype()` 은 이제 `battle-start-feedback` 을 기록해 전투 장면에 `전투 시작 btl_b1` 배너를 즉시 렌더링하고, `tools/verify_candidate_battle_browser.py` 는 일반 `Enter -> 전투 btl_b1` action path 와 `encounter=1` 필드 전투 path 양쪽에서 `battleStartFeedbackRender=True`/`battleStartFeedbackDuration=1000` 을 확인한다. 이는 후보 전투 진입이 브라우저 캔버스에서 명확히 보이도록 한 웹 프로토타입 피드백이며, 원본 event-driven battle entry 나 encounter runtime 구현 증거로 승격하지 않는다.
- 2026-06-06 전투 시작/승리 WLK sound 증거 보강: `startBattlePrototype()` 은 전투 시작 `battle-start-feedback` 결과에 `battleStartSound=battleStart` 를 붙이고, 후보/필드 전투 승리 경로는 `victorySound=victory` 를 `HWANSE_LAST_BATTLE_PROTOTYPE` 및 승리 auto-save marker 에 남긴다. `tools/verify_candidate_battle_browser.py` 는 8013 기준 action battle/dialogue battle/field encounter 시작에서 `battleStartSoundSrc=../extract_wlk/08.wav`, 후보 전투 완료/필드 전투 승리에서 `victorySoundSrc=../extract_wlk/12.wav` 를 확인한다. 이는 전투 시작/승리 피드백을 추출 WLK 오디오 이벤트에 연결한 웹 gameplay 보강이며, 원본 battle UI loop, DirectSound mixing/timing, reward table, encounter table, story flag proof 로 승격하지 않는다.
- 2026-06-07 전투 시작 overlay WLK battleStart sound marker 보강: `recordBattleStartFeedback()` 은 이제 전투 시작 overlay log/render snapshot 에 `battleStartSound=battleStart`, `battleStartSoundSrc=../extract_wlk/08.wav`, `battleStartSoundPlayed=True` 를 정식 필드로 남긴다. `startBattlePrototype()` 은 기존처럼 `battleStart` WLK 사운드를 한 번 재생한 뒤 `attachBattleStartFeedbackSound()` 로 같은 sound entry 를 overlay 에 연결하므로 summary 와 feedback entry 가 같은 효과음을 가리킨다. 8013 기준 `tools/verify_candidate_battle_browser.py` 는 action battle, dialogue battle link, field encounter 시작 경로에서 `battleStartFeedbackSound=battleStart:../extract_wlk/08.wav:True` 를 확인하고, `tools/verify_web_assets.py` 와 `tools/summarize_completion_audit.py` 는 candidate battle smoke JSON/MD 및 completion audit evidence 에 같은 marker 를 요구한다. 이는 전투 시작 표시가 overlay, battle summary, WLK 시작 효과음을 같은 gameplay feedback 단위로 남기도록 하는 웹 구현 보강이며, 원본 battle UI loop/DirectSound timing/event-driven battle proof 로 승격하지 않는다.
- 2026-06-08 추출 적/오브젝트 스프라이트 전투 선택 보강: `tools/build_web_assets.py` 와 `tools/export_battle_enemy_candidates.py` 는 `boss*.cns`/`z*.cns` 65개 적/오브젝트 스프라이트 PNG 를 모두 runtime asset table 에 싣고, `legacy aggregate asset workbench (removed)` 과 `out/battle_enemy_candidates.*` 에 `extractedEnemySpriteAssetCount=65`, `assetCount=65` 를 남긴다. `web/index.html` 의 `전투 선택` 메뉴는 현재 맵에 맞는 이벤트 기반 후보와 별도로 65개 스프라이트 전용 후보를 추가하고, 선택 시 `source=prototype-battle-sprite-menu`, `spriteOnly=True`, `enemyProfileSource=generated-extracted-sprite-profile`, `battleEnemySpriteSelectionKind=extracted-sprite-only-prototype`, `sourceBacked=False` 로 전투 장면을 시작한다. `tools/verify_candidate_battle_browser.py` 는 8013 기준 `map2_14j` 메뉴에서 `zk_big.cns` 를 선택해 `menuCount=69`, `eventCount=4`, `spriteCount=65`, `selected=sprite-only:zk_big`, `battleStartFeedback=전투 시작 btl_j1` 을 확인한다. 이는 추출된 몬스터/오브젝트 그래픽을 웹 gameplay 에서 모두 볼 수 있게 하는 보강이며, 원본 enemy row, encounter/formation table, reward table, combat formula, event-driven battle entry proof 로 승격하지 않는다.
- 2026-06-09 legacy aggregate workbench 적/오브젝트 카운트 표면 보강: `legacy aggregate asset workbench (removed)` 은 상단 summary 와 `removed legacy workbench marker` 에 `enemy sprites 58`, `object sprites 7`, `enemy+object 65/65`, EXE sprite descriptor refs `65`, referenced payloads `64`, missing `zky_nmk.cns` 를 직접 노출한다. `enemy` 필터만 보면 58개지만 `sprite` 필터는 적+오브젝트 합산 65개를 보여주며, 상단 `전투 근거`/`액션 핸들러` 링크는 `out/original_battle_data_gap.html` 과 `out/battle_action_handler_context.html` 로 이어진다. 같은 상단에는 `Route 근거`/`Hotspot 후보` 링크도 추가해 `out/route_promotion_external_proof_handoff.html` 과 `out/strict_source_hotspot_external_review_packet.html` 로 바로 넘어가며, summary/READY marker 는 `route promotion blocked`, strict hotspot 후보 `4`, proof `false`, tile `false`, reject `selector-only-scene-list-no-strict-hotspot` 를 함께 노출한다. 같은 summary/READY marker 는 `original enemy rows proven false`, `action handler 0x36`, `battle-action-handler-grounded-entry-dispatch-missing`, `storage false` 를 노출해 추출 sprite 수와 원본 전투 데이터 proof 상태를 분리한다. `removed asset workbench browser verifier --base http://127.0.0.1:8013` 와 `tools/verify_web_assets.py` 가 이 수치를 고정한다. 이는 추출된 몬스터/오브젝트 그래픽이 빠진 것이 아니라 viewer category split 때문임을 명확히 하고, route promotion blocker 를 legacy aggregate workbench 에서도 놓치지 않게 하는 UI/증거 보강이며, 여전히 원본 enemy row/stat/formation proof 또는 normal-route proof 로 승격하지 않는다.
- 2026-06-10 legacy aggregate workbench 관리형 워크벤치 보강: `legacy aggregate asset workbench (removed)` 은 게임풍 화면이 아니라 일반 웹 자산 검토 화면 안에 `자산 워크벤치` 표를 추가했다. 이 표는 전체 자산, 맵 소스/조립, 몬스터/공격, 음원/제목, 진행/증거 5개 행으로 나뉘며 `map_review.html`, `collision_review.html`, `monster_review.html`, `audio_review.html`, `out/audio_archive_manifest.html`, `out/audio_title_provenance.html`, `progress.html`, `out/route_promotion_external_proof_handoff.html` 로 바로 이동한다. 오른쪽 선택 자산 미리보기에는 선택한 PNG 소스와 함께 맵이면 맵/충돌 검토, 적/오브젝트면 몬스터 공격 프레임/전투 후보, 전투/캐릭터 asset 이면 해당 근거 페이지 링크가 자동으로 붙는다. `removed legacy workbench marker` 는 `browserAssetWorkbenchImplemented=True`, `workbenchRowCount=5`, `selectedPreviewReviewLinkCount` 를 노출했다. 이후 구식 aggregate workbench 와 tile review 페이지는 active surface 에서 제거했다. 이는 흩어진 자산/검토 표면을 보기 쉽게 묶은 UX/증거 탐색 보강이며, 원본 enemy row/stat/formation proof, normal-route proof, event VM proof 로 승격하지 않는다.
- 2026-06-06 전투 타격 WLK sound 증거 보강: 플레이어 공격/적 반격의 `recordBattleHitEffect()` 결과가 각각 `battleHit` 사운드 이벤트를 보존하게 했다. `tools/verify_candidate_battle_browser.py` 는 8013 기준 canvas pointer 공격 smoke 에서 `hitEffectTargets=enemy,party`, `battleHitSoundCount=2`, `battleHitSoundSrc=../extract_wlk/09.wav`, damage text render 를 함께 확인한다. 이는 전투 타격 이펙트와 추출 WLK 오디오 이벤트를 묶은 웹 gameplay 보강이며, 원본 combat formula, enemy AI, DirectSound mixing/timing proof 로 승격하지 않는다.
- 2026-06-10 전투 적 공격 프레임 후보 런타임 연결 보강: `monster_review.html` 의 공격 후보 표와 같은 `primary-command`/`linked-action-text`/`special-or-reaction` 프레임 run 개념을 `web/game.html` 전투 반격 렌더에 연결했다. 적 반격 턴은 `recordBattleEnemyAttackAnimation()` 으로 `prototype-enemy-attack-animation` marker 를 남기고, 선택된 후보의 frame run 을 적 스프라이트 source rect 로 순차 적용하며 짧은 lunge 를 그린다. `tools/verify_candidate_battle_browser.py` 는 8013 기준 `map1_02b` canvas pointer 공격 smoke 에서 `푸른 마수`/`zky_ao.cns`/`할퀴기` 가 `enemyAttackAnimation=primary-command`, `enemyAttackFrames=0,1,2,3`, `enemyAttackDrawn=True`, `browserEnemyAttackAnimation=True`, `prototypeMonsterAttackFrameRuntime=True`, `originalAttackSequenceBound=False`, `originalEnemyAi=False` 로 남는지 확인한다. 같은 smoke 의 `event-dialogue-block-038:btl_n2` 상태이상 턴은 `철갑 코뿔`/`zkb_sai.cns`/`독액` 이 `enemyAttackAnimation=special-or-reaction`, `enemyAttackFrames=3,4,5,0`, `enemyAttackDrawn=True`, `secondEnemyAttackAnimation=special-or-reaction` 으로 렌더되는지도 확인한다. `monster_review.html` proof matrix 는 `browser-runtime-attack-frame-animation` passed row 를, `battle_analysis.html` proof matrix 는 `browser-enemy-attack-frame-animation` passed row 를 추가해 이 구현이 관리자 검토 화면에서도 보이게 했다. 이는 추출 enemy/object sprite 와 후보 프레임을 실제 웹 전투 화면에서 볼 수 있게 하는 gameplay 보강이지만, 원본 attack sequence, enemy AI, combat formula, story flag proof 로 승격하지 않는다.
- 2026-06-10 아군 전투 액션 프레임 런타임 연결 보강: 아군 공격/기술 입력도 `btl_at.cns`/`btl_rs.cns`/`btl_sm.cns` 전투 시트의 grid frame 을 쓰도록 `recordBattlePartyActionAnimation()` 과 `battlePartyActionAnimationRenderState()` 를 추가했다. `map1_02b` canvas pointer 공격 smoke 는 Ataho `정권` 입력에서 `partyActionAnimation=attack`, `partyActionAsset=battle_ataho`, `partyActionCns=btl_at.cns`, `partyActionFrames=1,2,3,4`, `partyActionDrawn=True`, `browserPartyActionAnimation=True`, `prototypePartyActionFrameRuntime=True`, `originalPartyActionSequenceBound=False` 를 남기고, 같은 턴의 `turnResult`/auto-save payload 와 `battle_analysis.html` proof matrix 의 `browser-party-action-frame-animation` passed row 도 이를 확인한다. 8013 기준 `tools/verify_candidate_battle_browser.py` 는 별도 `battleSkillAction` smoke 에서 Ataho `돌려차기` 기술 실행도 `partyActionAnimation=skill`, `partyActionFrames=4,5,6,7`, `partyActionDrawn=True`, `prototypePartyActionFrameRuntime=True`, `skillTextTable=atahoActions`, `skillTextIndex=1`, `originalSkillFormulaImplemented=False` 로 남는지 확인한다. 같은 smoke 는 `partySkillFrameActors=Ataho,Rinshan,Smashu`, `partySkillFrameAssets=battle_ataho,battle_rinshan,battle_smash`, `partySkillFrameCns=btl_at.cns,btl_rs.cns,btl_sm.cns`, `partySkillFrameHeights=80,80,48`, `partySkillFrameDrawn=True,True,True` 로 3인 기술 프레임 렌더 snapshot 도 고정하며, `battle_analysis.html` 은 같은 row 에 skill frame marker 를 노출한다. 이 작업은 이미 추출한 전투 캐릭터 스프라이트를 웹 전투 체감에 연결하는 보강이며, 원본 player attack sequence, 전투 formula, story flag proof 로 승격하지 않는다.
- 2026-06-06 전투 적 행동명 EXE text-table provenance 보강: `battleEnemyPrototypeAction()` 은 행동 선택/AI 는 계속 `prototype-enemy-action` 으로 두되, 행동명 텍스트가 `battleCommands` EXE text table entry 에서 왔음을 별도 필드로 노출한다. WebKit battle smoke 는 `할퀴기` 가 `battleCommands[3]` / `0x004d29a4 -> 0x004d438c`, `돌진` 이 `battleCommands[8]` / `0x004d29e4 -> 0x004d447c`, `독액` 이 `battleCommands[12]` / `0x004d2a0c -> 0x004d4512` 에서 온다는 `enemyActionNameSource=exe-text-table-battleCommands` 증거를 확인한다. 이는 후보 전투의 표시 텍스트 provenance 를 EXE 자산에 더 직접 연결하는 보강이며, 원본 enemy row, AI, 전투 공식, reward/drop table, event-driven battle entry 는 계속 미증명이다.
- 2026-06-06 전투 플레이어 명령명 EXE text-table provenance 보강: `battleCharacterAction()` / `battleSkillCommands()` 는 command item 에 `nameSource`, text-table key/index/ref/text VA 를 싣고, 전투 실행 결과/skill feedback/auto-save/turn result 에 같은 provenance 를 전달한다. WebKit mobile smoke 는 일반 공격 `Ataho 정권` 이 `atahoActions[0]` / `0x004d24ac -> 0x004d2d8c`, 다음 actor `Rinshan 유미쌍조` 가 `skillNamesB[0]` / `0x004d2c04 -> 0x004d4d68`, savedat 스킬 `Ataho 돌려차기` 가 `atahoActions[1]` / `0x004d24b4 -> 0x004d2daa`, `Rinshan 장궁` 이 `skillNamesB[7]` / `0x004d2c5c -> 0x004d4ee2`, `Smashu 투구쪼개기` 가 `skillNamesB[2]` / `0x004d2c2c -> 0x004d4e1e` 에서 온다는 evidence 를 확인한다. 이 변경은 전투 command 표시/실행 provenance 를 EXE text table 에 더 단단히 묶는 보강이며, 원본 전투 공식/AI/skill formula/story flag proof 로 승격하지 않는다.
- 2026-06-06 전투 공통 command EXE text-table provenance 보강: `battleCommandTextItem()` 은 `도주`/`방어` command item 을 `battleCommands` entry provenance 와 함께 만든다. Candidate battle WebKit smoke 는 `도주` 가 `battleCommands[0]` / `0x004d2974 -> 0x004d42f6` 로 `battle-run` 진행 기록과 auto-save 에 남고, 패배 전 선택된 `방어` 가 `battleCommands[1]` / `0x004d297c -> 0x004d4314` 로 battle turn result, `battle-defeat` 진행 기록, auto-save 에 남는지 확인한다. 이는 비승리 전투 outcome 의 표시/실행 provenance 를 EXE command text table 에 연결하는 보강이며, 원본 battle UI command loop, enemy AI, story flag, reward/drop/formula proof 로 승격하지 않는다.
- 2026-06-06 전투 방어 overlay 보강: `방어` 명령으로 적 반격 피해를 줄인 턴도 battle log/자동 저장에만 묻히지 않게 전투 화면 위에 `방어 피해 2` overlay 를 0.9초 동안 표시한다. `web/index.html` 은 `HWANSE_BATTLE_DEFEND_FEEDBACK_LOG`, `HWANSE_LAST_BATTLE_DEFEND_FEEDBACK`, `HWANSE_BATTLE_DEFEND_FEEDBACK_RENDER`, `HWANSE_LAST_BATTLE_DEFEND_FEEDBACK_RENDER` 를 노출하고, 8013 기준 candidate battle defeat smoke 는 `defendFeedback=battle-defend-feedback:방어 피해 2`, `defendFeedbackRender=True`, `defendFeedbackDuration=900`, `browserDefendFeedback=True` 를 확인한다. 이 피드백은 browser-local 방어 턴 결과를 즉시 보이게 하는 gameplay UX 보강이며, 원본 battle UI command loop, enemy AI, combat formula, story flag proof 로 승격하지 않는다.
- 2026-06-07 전투 비승리/방어 WLK sound marker 보강: 도주 결과 feedback 은 이미 재생되는 `transition` WLK(`../extract_wlk/07.wav`)를 `battleOutcomeSound` 로 남기고, 패배 결과 feedback 과 방어 피해 overlay 는 마지막 적 반격의 `battleHit` WLK(`../extract_wlk/09.wav`)를 각각 `battleOutcomeSound`/`battleDefendSound` 로 보존한다. `tools/verify_candidate_battle_browser.py` 는 8013 기준 `runBattle` 에서 `outcomeSound=transition`, `defeatBattle` 에서 `defendSound=battleHit` 및 `outcomeSound=battleHit` 이 log/render/auto-save 에 남는지 확인한다. 이는 비승리 전투 결과와 방어 feedback 을 추출 WLK 오디오 이벤트에 연결한 웹 gameplay evidence 이며, 원본 DirectSound timing, battle loop, combat formula, enemy AI, story flag proof 로 승격하지 않는다.
- 2026-06-07 전투 비승리 완료 알림 feedback 보강: `startCompletedBattleOutcomeNotice()` 는 도주/패배 진행이 복원된 목표 실행에서 완료 대화만 띄우지 않고 `battle-outcome-completion-notice-feedback` overlay 도 함께 기록한다. 이 완료 알림은 `전투 도주 완료 1/1` 또는 `전투 패배 완료 1/1` 텍스트와 `menuConfirm` WLK(`../extract_wlk/04.wav`) sound marker 를 남기며, `tools/verify_candidate_battle_browser.py` 는 8013 기준 `runBattle`/`runTitleContinue`/`defeatBattle`/`defeatTitleContinue` 에서 `outcomeNoticeFeedbackRender=True` 및 `outcomeNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 확인한다. 이는 browser-local 비승리 결과 목표 완료를 플레이어에게 명확히 보여주는 웹 gameplay 보강이며, 원본 reward/story flag 실행 또는 event-driven battle outcome proof 로 승격하지 않는다.
- 2026-06-06 도구 사용 EXE item text-table provenance 보강: `useInventoryItem()` / `useBattleItem()` 은 실행 결과, `item-use-prototype` progress detail, auto-save, inventory/battle feedback log/render 에 `itemNameSource=exe-text-table-items` 와 `itemTextTable*` fields 를 남긴다. 전투 turn auto-save 도 도구 command 일 때 같은 item name table 을 `commandTextTable*` 로 싣는다. WebKit smoke 는 `약초` 가 `items[0]` / `0x0048b984 -> 0x0048ba7c`, `해독초` 가 `items[1]` / `0x0048b98c -> 0x0048ba8e`, `마법의 물약` 이 `items[3]` / `0x0048b99c -> 0x0048bab2`, `마수석` 이 `items[5]` / `0x0048b9ac -> 0x0048bad6` 에서 온다는 실행 provenance 를 확인한다. 이는 웹 프로토타입 도구 표시/실행 provenance 를 EXE text table 에 연결하는 보강이며, 원본 item formula, 상태 flag offset, inventory/money/story flag runtime proof 로 승격하지 않는다.
- 2026-06-07 전투 도구 대상 선택 보강: 다인 파티에서 전투 `도구` 명령은 바로 첫 회복 대상에 적용하지 않고 party target menu 를 열어 `Ataho/Rinshan/Smashu` 중 선택한 대상에게 적용한다. `web/index.html` 은 `battle-item-target-selection` marker 와 target list snapshot 을 남기고, `tools/verify_candidate_battle_browser.py` 는 8013 기준 약초 x2 상태에서 Rinshan HP `8->28`, 약초 `2->1`, `itemAutoSource=item-use-prototype`, `turnAutoSource=battle-turn-prototype`, saved HP/item payload 복원을 확인한다. 이는 웹 gameplay 의 전투 도구 조작성을 보강한 것이며, `originalItemEffectFormulaImplemented=False` 와 story/status formula gap 은 유지한다.
- 2026-06-07 필드 도구 대상 선택 보강: 맵 runtime menu 의 도구 사용도 여러 유효 대상이 있을 때 바로 첫 대상에 적용하지 않고 `inventory-item-target-selection` 대상 메뉴를 연다. `web/index.html` 은 `pendingInventoryItem`/`item-target` menu mode 와 open/selected marker 를 남기고, `tools/verify_title_start_browser.py` 는 8013 기준 Ataho/Rinshan 이 함께 손상된 새 게임 상태에서 약초 대상 `Rinshan` 선택, Rinshan HP `8->38`, Ataho HP `24` 유지, 약초 `2->1`, `autoSource=item-use-prototype`, `inventoryFeedback=inventory-item-use:herb:약초 HP +30`, WLK item sound `../extract_wlk/11.wav` 를 확인한다. 이는 웹 gameplay 의 필드 도구 조작성을 보강한 것이며, `originalItemEffectFormulaImplemented=False` 와 story/status formula gap 은 유지한다.
- 2026-06-05 대사 완료 -> 후보 전투 연결 보강: 후보 대사 `event-dialogue-block-015` 를 끝까지 넘기면 같은 blockId 의 전투 후보 `event-dialogue-block-015:btl_b1` 이 `dialogue-battle-link` 진행으로 기록되고, 현재 목표가 `후보 대사 전투 btl_b1` / `전투 시작` 으로 바뀐다. 이후 일반 필드 액션 프롬프트도 `Enter -> 대사 전투 btl_b1` 로 바뀌며, Enter/A 실행은 `dialogue-battle-action` 으로 같은 전투를 시작하고 `battleStartFeedback=battle-start-feedback:전투 시작 btl_b1`, `prototypeDialogueBattleLinkImplemented=True`, `autoSource=dialogue-battle-link` 를 남긴다. `tools/verify_candidate_battle_browser.py` 는 이 dialogue-complete -> action prompt -> battle start 루프가 partial VM replay 와 `zky_ao.cns` 적 시각 후보를 보존하는지 확인한다. 이는 브라우저-local prototype 진행 연결이며 원본 event-driven battle entry, 전투 이벤트 실행, story flag proof 로 승격하지 않는다.
- 2026-06-05 오브젝트 연결 대사 -> 후보 전투 액션 보강: `map2_03l` 의 `zg_kni`/`zm_2`/`zs_rg` 오브젝트 조사는 연결 대사 `event-dialogue-block-004`, `032`, `041` 을 순서대로 진행하고, 완료 상태를 quick-load/title `이어하기 map2_03l 11,11` 로 복원한 뒤 일반 액션 프롬프트를 `Enter -> 대사 전투 btl_l1` 로 유지한다. 이 상태에서 Enter/A 는 완료 오브젝트 알림에 막히지 않고 `event-dialogue-block-041:btl_l1` 을 `dialogue-battle-action` 으로 시작하며, 전투 배경 `btl_l1`, 적 `백호 괴수`, 적 스프라이트 `zjk_byk.cns`, `battleStartFeedback=battle-start-feedback:전투 시작 btl_l1`, `dialogueBattleLinkCount=3`, `battleStartCount=1` 을 남긴다. 같은 smoke 는 이 전투를 실제 공격으로 승리 처리해 맵으로 돌아온 뒤 `autoSource=battle-victory`, `battleVictoryCount=1`, `drop=해독초`, `rewardEffect=battle-victory:백호 괴수` 를 확인하고, 남은 연결 전투 `event-dialogue-block-032:btl_l2` 와 `event-dialogue-block-004:btl_l1` 도 순서대로 승리해 `battleStartCount=3`, `battleVictoryCount=3`, `pendingLink=None`, `dropCount=3`, 최종 `Enter -> 전투 완료 btl_l1` 프롬프트와 `battle-complete:event-dialogue-block-004` 완료 알림(`duplicateProgress=True`)까지 확인한다. `tools/verify_candidate_event_object_browser.py` 와 completion audit verifier 는 이 오브젝트 조사 -> 연결 대사 -> 전투 체인 -> 완료 알림 루프를 확인한다. 이는 브라우저-local prototype 액션 연결이며 원본 NPC/object VM, event-driven battle entry, story flag proof 로 승격하지 않는다.
- `web/battle_analysis.html` 과 `out/battle_enemy_candidates.json` 은 21개 battle review 후보를 8개 EXE-nearest `z*`/`boss_*` 적/오브젝트 sprite 시각 후보로 연결한다. 웹 전투 화면은 이제 `event-dialogue-block-015:btl_b1 -> zky_ao.cns` 같은 원본 sprite asset 을 placeholder 대신 렌더링할 수 있지만, 이 매핑은 EXE resource descriptor 근접 근거일 뿐 enemy row, stats, formation/encounter table, reward table, combat formula, battle-entry event execution 증거가 아니므로 완료 승격하지 않는다.
- `out/original_battle_data_gap.html` 은 전투 그래픽/텍스트 자산과 원본 battle data 를 분리한다. 현재 `z*`/`boss_*` 적/오브젝트 스프라이트 이미지 65개, 보스 이미지 2개, `btl_*` 전투 스프라이트 8개, battle/action 텍스트 82개는 추출됐고 EXE resource descriptor 도 위처럼 grounded 되었지만 enemy row 와 sprite binding, formation/encounter table, reward table, combat formula 는 모두 미증명으로 남긴다.
- 2026-06-07 `out/original_battle_numeric_context.html` 은 battle/background/enemy resource descriptor 주변 EXE dword context 123개와 EXE-nearest battle/enemy 후보 pair 21개를 별도 스캔한다. 1024바이트 이내 close pair 9개와 descriptor-local small-number run 32개가 관찰되지만, handler edge, row stride, formation/reward binding, runtime execution proof 가 없어 promotable enemy row/reward row 는 0개로 남긴다. `out/original_battle_data_gap.html`, `out/event_battle_gap_audit.html`, completion audit 은 이 값을 반영하되 원본 enemy stats/formations/rewards/formulas 로 승격하지 않는다.
- `out/savedata_sample_deltas.html` 은 public savedat 6개를 비교할 때 route-critical offset뿐 아니라 1274바이트 저장 파일의 semantic coverage 도 함께 기록한다. 현재 editor-backed scene/money/item/character stat/skill 필드는 160/1274바이트만 의미가 확인됐고, 1114바이트와 public sample 사이에서 변하는 unmapped 248바이트는 장비 소유/equipped slot, 원본 상태 플래그, story/event flag offset 증거로 승격하지 않는다.
- 2026-06-11 savedata review 의미/오프셋 경계 보강: `web/savedata_review.html` 에 `세이브 의미/오프셋 경계` 표를 추가해 public savedat semantic coverage(known 160/1274, unknown 1114), legacy public editor scope(stat controls 46, selector/route proof false), runtime save loader boundary(`load=0x00423319`, `selectorStore=0x004234ba`, `selectedPointerGlobal=0x0059de30`), route-critical selector offsets(`0x0002=0x02`, `0x0003=0x00`), selector-distinguishing byte set 102개, unknown/varying ranges 27개, original equipment/status/story offset missing 상태를 분리했다. `HWANSE_LAST_SAVEDATA_REVIEW_RENDER` 는 `browserSavedataOffsetBoundaryImplemented=True`, `savedataOffsetBoundaryRowCount=7`, `savedataOffsetBoundaryGroundedRowCount=3`, `savedataOffsetBoundaryBlockedRowCount=2`, `savedataOffsetBoundaryPartialRowCount=1`, `savedataOffsetBoundaryMissingRowCount=1`, `savedataLegacyEditorSelectorEvidenceFound=False`, `savedataRuntimeSavePromotionAllowed=False`, `savedataOriginalEquipmentStatusStoryOffsetsMissing=True` 를 남긴다. 이는 public savedata와 편집기/loader 근거를 관리 화면에서 선명하게 보여주기 위한 UX/증거 경계 보강이며, selector `2:0`, 장비/상태/story 원본 오프셋, route promotion proof 로 승격하지 않는다.
- `map1_01a.cns` 등 필드 맵은 대부분 `u16 width, u16 height, u16 layer0[width*height], u16 layer1[width*height]` planar 맵 레이어 후보로 확인. `map0_01n.cns` 는 `u8 width, u8 height` compact header 변종이다. 인접 u16 을 칸 단위 pair 로 보는 후보는 하나의 연속 맵을 좌우 반복 덩어리처럼 쪼개서 폐기.
- `tools/export_map_js.py` 와 `tools/build_web_assets.py` 로 현재 웹 프로토타입 자산 생성을 재현 가능하게 구성.
- `tools/build_web_assets.py` 는 모든 필드 맵 174개를 리뷰/분석용 `out/maps.js` 에 포함하고, `/web/` 게임 런타임용으로 전환/디버그 대상 맵의 작은 인덱스 `out/maps_runtime.js` 와 맵별 chunk `out/maps_runtime_chunks/*.js` 도 생성한다.
- `legacy aggregate asset workbench (removed)` 은 생성된 top-level PNG 132개, `extract_wlk/00.wav`..`53.wav` 효과음, `extract_mlk/00.mid`..`19.mid` 음악을 검색/분류해서 확인하는 legacy aggregate workbench다. 오디오 표기는 EXE 내부 zero-based id로 통일하며, WLK는 `WLK id 00..53`, MLK는 `MLK id 00..19`만 사용자-facing 번호로 쓴다. WLK 내부에는 effect title 필드가 없으므로 browser cue 사용처는 provenance로만 남기고 제목 없는 항목은 EXE id entry로 표시한다. MLK는 embedded MIDI title이 있으면 제목을 쓰되 제목 없는 항목은 `MLK id NN`으로 표시한다.
- 2026-06-11 WLK id 45 관련 이전 청취 보정은 폐기했다. 현재 계약은 `WLK id 45`가 `extract_wlk/45.wav`를 직접 가리키는 EXE id 체계이며, asset/audio review 모두 raw `extract_wlk/*.wav` 를 그대로 재생한다. `tools/verify_audio_archive_manifest.py`, `removed asset workbench browser verifier`, `tools/verify_home_landing_browser.py` 는 WLK 별도 probe 없이 manifest 기반 raw playback 과 MLK soundfont preview 를 검증한다.
- 2026-06-09 audio title provenance 보강: `out/audio_title_provenance.html`/`.json`/`.md` 는 WLK 54개 embedded title 0개, browser cue provenance 9개, EXE id entry 45개와 MLK 20개 embedded MIDI title 16개/no-title 4개(`MLK id 02`, `MLK id 06`, `MLK id 11`, `MLK id 17`)를 고정한다. `MIDDATA.MLK` 는 `u8 count` 뒤에 `flag/u32 offset/u32 size` 9B entry 20개가 붙고 첫 payload 는 `1 + 20*9 = 181` 에서 `MThd` 로 시작한다. `legacy aggregate asset workbench (removed)` 의 `제목 출처` 링크는 이 provenance 페이지로 바로 이동한다.
- 2026-06-10 audio review 제목 목록 보강: `web/audio_review.html` 에 `음원 제목 목록` 표를 추가해 `out/audio_title_provenance.json` 의 WLK 54개와 MLK 20개 표시명 출처를 한 화면에서 모두 볼 수 있게 했다. WLK 표는 `step`/`dialogue`/`battle hit` 같은 browser cue usage label 9개와 `WLK id NN` fallback 45개를 `no embedded WLK name` 제목 저장 판정과 함께 보여주고, MLK 표는 embedded MIDI title 16개(`大ボス戦闘１` 포함)와 `MLK id NN` fallback 4개를 사용처 label 과 분리해서 보여준다.
- 2026-06-11 audio review 원본 런타임 플레이백 경계 보강: `web/audio_review.html` 에 `원본 런타임 플레이백 경계` 표를 추가해 WLK loader entry 해석(`0x0042a5bb`), DirectSound buffer/WAVEFORMATEX 경로(`0x0042af73`), `DirectSoundCreate` import, `WINMM.dll` MIDI stream import(`midiStreamOpen`/`midiStreamOut`), WLK/MLK title provenance, raw WLK browser playback, MLK soundfont scheduling, browser browser cue smoke 를 한 화면에서 분리했다. `HWANSE_LAST_AUDIO_REVIEW_RENDER` 는 `browserAudioRuntimeBoundaryImplemented=True`, `audioRuntimeBoundaryRowCount=4`, raw archive manifest completion, soundfont smoke status, DirectSound/WinMM runtime proof separation 을 남긴다. 이는 WLK/MLK 추출/브라우저 미리듣기와 원본 DirectSound mixer/loop 및 WinMM MIDI playback proof 를 분리해 보이기 위한 관리자 UX 보강이며, 원본 playback parity 완료 증거로 승격하지 않는다.
- 2026-06-08 legacy aggregate workbench 음원 카드의 첫 줄은 `battle hit · 09.wav`, `WLK id 45 · 45.wav`, `大ボス戦闘１ · 08.mid` 처럼 사람이 확인할 라벨과 EXE id 파일을 함께 보여준다. WLK 라벨은 임베디드 제목이 아니라 browser cue provenance 또는 EXE id entry이며, 두 번째 줄의 `PCMDATA.WLK · browser cue provenance/EXE id entry · no embedded WLK name` metadata 로 이 provenance 를 계속 구분한다. MLK 도 MIDI track-name 이 없는 항목은 `EXE id entry · no embedded MIDI title` 로 표시한다.
- 웹 게임 런타임은 추출된 WLK 효과음 일부를 `SOUND_ASSETS` 로 연결해 걷기, 대사 넘김, 메뉴, 맵 전환, 전투 시작/타격/승리에 사용한다. `playSound()` 는 `HWANSE_SOUND_LOG`/`HWANSE_SOUND_COUNTS` 에 요청 이력을 남기며, `tools/verify_mobile_browser_controls.py` 는 8013 기준 WebKit smoke 에서 터치 이동 후 `step`, 대사 열기/넘김 후 `dialogue`, 전투 시작/공격/승리 후 `battleStart`/`battleHit`/`victory` 카운트가 증가하는지 확인한다. 런타임 메뉴는 별도 `runtime-menu-sound` marker 를 남겨 모바일 `☰` 열기/키보드 이동/닫기 흐름이 `menuConfirmSoundCount=2`, `menuMoveSoundCount=1`, `menuSound=runtime-menu-sound:open,move,close`, `../extract_wlk/04.wav`, `../extract_wlk/03.wav` 로 검증된다. 이는 추출 WLK 자산을 웹 gameplay 액션에 연결한 증거이며, 원본 DirectSound mixing/타이밍 완전 재현 증거는 아니다.
- 2026-06-08/11 WLK entry table 확정: `tools/extract_wlk.py` 는 `tools/audio_archive_manifest.py` 의 사용자 검증 54개 행을 기준으로 `WLKF0200` entry offset/sample rate/bit depth/gain 을 검증하고, 각 payload 를 raw PCM WAV container 로 쓴다. 출력 파일명과 사용자-facing 번호는 EXE zero-based id 기준 `extract_wlk/00.wav`..`53.wav`, `WLK id 00..53` 으로 통일한다. 16-bit 항목은 7개, 8-bit 항목은 47개, loop flag `0x20` 항목은 4개다.
- 2026-06-06 title menu WLK 효과음 마커 보강: 첫 화면 메뉴의 `ArrowDown`/`ArrowUp` 이동은 `title-menu-sound:move` 로 `../extract_wlk/03.wav` 를 남기고, 기본 `처음부터` 행에서 `Enter`, canvas pointer, 모바일 A 선택은 `title-menu-sound:select` 로 `../extract_wlk/04.wav` 를 남긴다. `tools/verify_title_menu_sound_browser.py` 는 8013 기준 WebKit에서 실제 keydown/canvas pointer/virtual A 이벤트를 dispatch 해 `titleMenuSound=title-menu-sound:move,move,select`, `inputSources=keyboard,keyboard,keyboard`, `inputSources=canvas-pointer`, `inputSources=mobile-action`, `menuMoveSoundCount=2`, `menuConfirmSoundCount=1`, `browserTitleMenuSound=True` 를 확인하고, 각 선택 직후 `map1_02b` 시작까지 이어지는지도 검증한다. 이는 첫 화면 조작도 입력 source 별 추출 WLK 피드백을 갖도록 하는 웹 gameplay UX 보강이며, 원본 title/menu DirectSound timing 또는 story flag proof 로 승격하지 않는다.
- 2026-06-06 MIDDATA.MLK runtime music cue/BGM synth 보강: `web/index.html` 은 title/map/battle 장면에 각각 `../extract_mlk/00.mid`, `../extract_mlk/01.mid`, `../extract_mlk/08.mid` cue 를 연결하고 `HWANSE_LAST_MUSIC_CUE`/`HWANSE_MUSIC_CUE_LOG` 에 `runtime-music-cue` marker 를 남긴다. 첫 키/포인터 입력 뒤에는 같은 추출 MIDI 파일을 fetch 해 browser WebAudio oscillator synth 로 note on/off 이벤트를 스케줄하고 `HWANSE_LAST_MUSIC_SYNTH`/`HWANSE_MUSIC_SYNTH_LOG` 에 `runtime-midi-synth-playback` 을 남긴다. `tools/verify_runtime_music_cue_browser.py` 는 8013 기준 WebKit에서 title, `map1_02b`, `battle=1` 진입을 열어 `cue=title|map|battle`, `archive=MIDDATA.MLK`, `browserMusicCue=True`, `synth=scheduled`, `browserMidiSynth=True`, title/map 420 notes, battle 380 notes 를 확인하고, battle summary 에 battle cue 가 보존되는지도 검증한다. 이는 추출 MIDI provenance 를 실제 브라우저 BGM 합성 재생 경로에 연결하는 웹 gameplay 보강이며, 원본 DirectMusic 악기/믹싱/선곡 로직 proof 로 승격하지 않는다.
- 2026-06-06 전투 종료 BGM 복귀/겹침 방지 보강: `endBattlePrototype()` 은 이제 승리/도주/패배 등 전투 장면 종료 후 `recordMusicCue("map", { reason: "battle-end-map-return" })` 를 호출하고 `HWANSE_LAST_BATTLE_END_MUSIC_CUE` 에 map cue 를 남긴다. 새 cue 가 들어오면 `requestMusicSynthPlayback()` 은 MIDI fetch/parse 를 기다리기 전에 기존 active synth 를 즉시 `runtime-midi-synth-stop` 으로 중단하고 `HWANSE_LAST_MUSIC_SYNTH_STOP`/`HWANSE_MUSIC_SYNTH_STOP_LOG` 에 이전 cue, 다음 cue, stop reason 을 남긴다. `tools/verify_candidate_battle_browser.py` 는 8013 기준 field encounter 전투에서 시작 직후 `battleMusicCue=battle`, `battleMusicSrc=../extract_mlk/08.mid` 를 확인하고, 승리 후 맵 복귀 상태에서 `mapMusicCue=map`, `mapMusicSrc=../extract_mlk/01.mid`, `battleEndMusicReason=battle-end-map-return`, `musicStop=battle->map`, `musicStopReason=cue-change`, `musicStopImplemented=True` 를 확인한다. 이는 실제 플레이 중 전투 BGM 이 맵으로 돌아온 뒤 계속 남거나 새 map BGM 과 겹치지 않도록 하는 웹 gameplay 보강이며, 원본 DirectMusic/전투 루프/선곡 proof 로 승격하지 않는다.
- `tools/render_map_preview.py` 로 웹 메타데이터와 같은 규칙의 맵 프리뷰 PNG 생성 추가. CLI 기본값은 진단용 `layer0` 이며, 실제 리뷰/런타임 기준 확인에는 `--visual-mode layer1UnderSceneTilesets` 를 사용한다.
- CNS 맵 렌더 검토는 완료된 후보 감사 산출물 대신 `web/map_review.html` 과 `web/map_gallery.html` 을 기준 화면으로 쓴다. `data/map_render_reviews.json` 은 174개 맵의 직접 accepted render row 를 보존하고, `tools/map_render_reviews.py` 는 병합/검증 후 `out/map_render_reviews.json`/`.js` 만 내보낸다.
- map render review 후보는 이제 `visual + tilesets` 뿐 아니라 `tileIndexMode` 도 함께 저장한다. 기존 `row40_zero` 리뷰 키는 그대로 호환하고, `row40`, `page20x6quad`, `page20x12`, `vflip40`, `column40x12` 같은 비기본 후보는 `<map>|<visual>|<tilesets>|<tileIndexMode>` 키로 export/merge 된다. 일반 게임 화면도 accepted/family default 리뷰의 `tileIndexMode` 를 적용하므로, 큰 구조는 맞지만 타일이 밀리거나 반복되어 보이는 맵을 별도 좌표계 후보로 확정할 수 있다. `web/map_review.html` 은 `tileIndexFilter=row40_zero|page20x6quad_zero|page20x6quad|row40|page20x12|vflip40|column40x12|all` 쿼리와 상단 tile index 필터를 지원한다. 큐와 source group 상세 페이지는 `tileIndexDeltaRatio` 가 큰 맵을 먼저 보여줘 잘못된 타일 인덱스 후보부터 확인하게 한다.
- `web/index.html` 의 normal/debug 런타임 모두 `row40_zero`, `page20x6quad_zero`, `page20x6quad`, `row40`, `page20x12`, `vflip40`, `column40x12` tile index mode 를 허용한다. 따라서 그룹 페이지의 `walk ...` 링크와 accepted render review 의 `tileIndexMode` 가 실제 Canvas 렌더링에 그대로 적용된다.
- family default 전파는 `familyDefault: true` 가 붙은 accepted 리뷰만 사용한다. 기존 기준 리뷰들은 이 플래그를 갖지만, 브라우저에서 새로 accept 한 borrower 리뷰는 export 시 기본적으로 플래그가 없으므로 같은 타일셋 계열 전체의 대표값으로 자동 승격되지 않는다.
- `tools/probe_tile_mapping.py` 로 맵별 타일 좌표계 후보를 비교 가능. `row40_zero` 가 현재 기본값이며, non-zero 값에서 1을 빼는 `row40` 후보는 길/벽 타일이 밀리는 결과로 기본 렌더링에서 제외했다.
- `tools/probe_map_layouts.py` 로 현재 기본인 앞/뒤 절반 planar 2레이어와, 폐기 후보인 interleaved 레이어 및 좌우/상하 타일쌍 후보를 비교 가능하다. compact header 맵도 같은 후보 렌더링으로 확인할 수 있다.
- `tools/verify_web_assets.py` 로 HTML 자산 참조, PNG 크기, 맵 레이어/타일셋/전환 스폰 유효성 검증 추가. 맵 visual audit PNG 는 맵 크기와 썸네일 한도에서 계산되는 정확한 프리뷰 크기를 검증해 2x/4x 반복 렌더 회귀를 잡는다.
- `tools/probe_exe_cns_groups.py` 로 `Hwanse2.exe` 의 CNS 파일명 배열을 추출해 맵/타일셋 로드 묶음 추정 가능.
- `out/exe_imports.json` 로 `Hwanse2.exe` import table 을 요약한다. 현재 `DDRAW.dll!DirectDrawCreate`, `DINPUT.dll!DirectInputCreateA`, `DSOUND.dll!DirectSoundCreate` import 가 확인되어 원본은 DirectDraw/DirectInput/DirectSound 기반이다.
- `out/directdraw_flow.html`/`.json` 과 `docs/DIRECTDRAW_NOTES.md` 로 원본 DirectDraw 초기화/표시 흐름을 정리했다. `DirectDrawCreate` 는 `0x00415602`/`0x00415618` 에서 thunk `0x00435d98` 를 거쳐 호출되고, 결과 `IDirectDraw*` 는 `0x004676c0` 에 저장된다. 정적 vtable 추적 기준 `SetCooperativeLevel`, `SetDisplayMode(640,480,8)`, `CreateSurface` 로 primary/offscreen/attached backbuffer 후보를 만들고, `0x004676e4`/`0x004676e8` 의 256-entry palette 를 `CreatePalette`/`SetPalette`/`SetEntries` 로 적용한다. 표시 경로는 fullscreen `Flip` 과 copy/windowed `Blt` 양쪽이 확인되며, 현재 웹 런타임의 640x480 Canvas 기준을 유지해야 한다는 근거로 문서화했다. draw-order/dirty-rect 세부 루틴은 아직 추가 추적 필요.
- `docs/DIRECTINPUT_NOTES.md` 에 원본 DirectInput 초기화/폴링 흐름을 정리했다. `DirectInputCreateA` 는 `0x0042eed0` 에서 호출되고, DirectInput 5 API(`0x0500`)로 `IDirectInputA*` 를 `0x00526f58` 에 저장한다. 장치 생성 후 `GetDeviceState(0x100, 0x0055b868)` 로 256바이트 키보드 state 를 읽고, pressed 판정은 `0x80` high bit 기반이다.
- `tools/summarize_input_keymap.py` 와 `out/input_keymap.md` 로 `0x0042f6d2` 의 16-action 키 매핑 테이블을 추출한다. primary table 기준 action 0-3 은 left/right/up/down 이고, arrow DIK 및 numpad 방향키가 함께 들어 있다. `0x0100` 이상 state offset 은 아직 보조 입력/확장 상태 생산 루틴 이름을 확정하지 않아 raw 값으로 보존한다.
- `docs/SAVEDATA_NOTES.md` 에 외부 세이브 에디터 `HDNua/HandyHwanseEditor` 의 C# 소스와 공개 save 파일에서 확인한 `savedat*.dat` offset 을 정리했다. 현재 근거로는 sample save 크기 1274바이트, 돈 3바이트 little-endian, 아이템 수량 1바이트, 캐릭터 스탯 2바이트 little-endian, 스킬 블록 byte encoding 을 확인했다. 원본 로더는 save 를 `0x004576d8`/`0x00457750`/`0x0059db60` 세 런타임 블록으로 읽고, save offset `0x0002`/`0x0003` 을 scene selector 로 써서 `0x00442d35` 테이블을 거쳐 선택 포인터를 `0x0059de30` 에 저장한다. `0x0004`/`0x0006` 은 런타임 `0x004576dc`/`0x004576de` 로 로드되어 object placement 에 쓰이는 tile/camera 좌표 후보로 확인했다. `tools/parse_savedata.py` 는 이 selector 와 좌표 후보, 연결된 CNS/field map 후보, 웹 시작 URL 후보를 JSON/Markdown 으로 해석하고, `HandyHwanseEditor` 의 disabled equipment UI labels 및 `out/text_tables.*` 장비명 후보가 savedat 장비 소유/equipped-slot offset 증거는 아니라는 `equipmentEvidence` 도 함께 보존한다. `tools/scan_savedata_slots.py` 는 `SAVEDATA/savedat1.dat`..`savedat9.dat`, 원본 EXE 케이스 `SaveData/savedat1.dat`..`savedat9.dat`, 그리고 양쪽 `.zip` 슬롯을 스캔해 `out/savedata_slot_scan.*` 를 만들고 selector `2:0`/selected pointer `0x00540714` route-evidence 후보를 우선 표시하되, 합성 selector probe fingerprint 는 `syntheticDiagnostic` 으로 분리해 실제 캡처 save 증거로 세지 않는다. `tools/extract_save_scene_selectors.py` 와 `out/save_scene_selectors.*` 는 전체 selector 94행/field map 86개를 인덱싱하고, HTML 인덱스는 selector/field map 링크를 바로 제공하며, 빌드는 selector-linked field map 을 `/web/` 런타임 chunk 에 포함한다. 웹은 `saveGroup`/`saveSlot` 쿼리, `publicSave` 쿼리, `savedatUrl` 쿼리, `savedatScan=1` 쿼리, `도구` 패널의 public savedat sample 선택지와 `scan SAVEDATA savedat1-9 dat/zip` 항목, `load savedat` 버튼 모두에서, 여러 selector 후보 중 좌표 후보가 bounds 안에 들어가는 맵을 먼저 골라 이동하고, money/known item counts/캐릭터 level 을 HUD 에 표시한다. 새 캡처 save 를 `SAVEDATA/savedat2.dat` 또는 `SaveData/savedat2.dat` 에 두면 `/web/game.html?savedatUrl=../SAVEDATA/savedat2.dat` 또는 `/web/game.html?savedatUrl=../SaveData/savedat2.dat` 로 같은 파서와 route evidence 판정을 바로 실행할 수 있고, 여러 슬롯을 `SAVEDATA` 또는 `SaveData` 아래 `savedat1.dat`..`savedat9.dat`/`.zip` 로 올리면 도구 패널 scan 항목 또는 `/web/game.html?savedatScan=1` 이 selector `2:0` 후보를 우선 로드한다. Rinshan/Smashu level 값이 있으면 동료 스프라이트 후보도 같이 표시한다. 로드한 save 가 current blocker 의 selector `2:0`/selected pointer `0x00540714`/`map1_01a -> map2_02d` route-pair 를 덮는지도 HUD 에 표시한다. 이 조건이 맞는 save 는 `routeAssist` 와 target `map2_02d` 를 자동으로 켜서 후보 출구 테스트로 바로 이어진다. 로드한 save 의 selector-linked field map 이 여러 개이면 `saveMapSelect` 로 같은 save 좌표를 유지한 채 후보 맵을 전환할 수 있고, save HUD 는 후보 수/좌표 in-bounds 수/현재 후보/route source-target 후보를 함께 표시한다. 샘플 `savedat2.dat` 는 `map1_01a`/`map1_02b`, flack3r 공개 `savedat2.dat` 는 target-side selector `1:0` 의 `map2_02d` 묶음, `savedat1.dat` 는 `map7_09k`..`map7_12k` 묶음과 연결된다. 스토리 플래그, 장비 소유/equipped-slot offset, 전체 아이템 이름과 selector 의 단일 field map/spawn 대응은 아직 별도 추적이 필요하다.
- `out/runtime_save_path_context.json` 은 원본 EXE 의 실제 save path 생성 근거를 별도로 고정한다. `savedat?.dat`, `savedat0.dat`, `SaveData\`, registry `SavePath` 문자열과 `FindFirstFileA`/`CreateFileA`/`ReadFile`/`RegQueryValueExA` 호출 지점을 묶고, explicit slot loader `0x00423319` 가 `savedat0.dat` 의 7번째 문자를 `slot_argument + 0x31` 로 바꿔 `SaveData\savedatN.dat` 를 열며 `0x00423404`/`0x00423430`/`0x0042345c` 세 `ReadFile` 뒤 `0x004234ba` 에서 `0x0059de30` 을 저장한다는 점을 문서화한다. `legacy savedata-load poll notes` 은 public captured save 를 임시 `SaveData/savedat1.dat` 로 둔 뒤 Enter/z/space/x 계열 load-menu 후보 sequence 8개를 polling했지만 1353 sample 모두 selector `8:0` 만 관측했고 selector `2:0`/current root 는 0회였다. `legacy multislot savedata-load poll notes` 은 public real saves 를 `SaveData/savedat1.dat`..`SaveData/savedat3.dat` 로 staged 해 selector `1:0`, `0:0`, `22:0` load 후보 6개/1266 sample 을 polling했지만 관측 selector 는 `8:0` 뿐이고 staged public selector/`2:0`/current root hit 는 0회였으며 cleanup 으로 임시 파일과 `SaveData` 디렉터리를 제거했다. `legacy multislot savedata case-alias poll notes` 은 원본 archive case alias 를 임시 생성한 같은 조건에서도 6개 sequence/1263 sample 모두 `8:0` 만 관측했고 public selector/`2:0`/current root hit 는 0회였다. `legacy multislot savedata input-path/case-alias poll notes` 은 input-path prelude 와 case alias 를 함께 둔 6개 sequence/1265 sample 에서 selector `50:0` 만 관측했고 staged public selector/`2:0`/current root hit 는 0회였다. `out/runtime_selected_pointer_synthetic_selector_2_0_input_path_case_alias_poll.json` 은 같은 input-path/case-alias 경로에 standalone synthetic selector `2:0` save-shaped 파일을 staged 했지만 2개 sequence/374 sample 모두 selector `8:0` 만 관측했고 staged selector/current root/route hit 는 0회였다. `out/runtime_selected_pointer_patched_public_selector_2_0_input_path_case_alias_poll.json` 은 public save 의 selector/position bytes 만 `2:0@34,19` 로 바꾼 diagnostic 을 같은 경로에서 staged 해 2개 sequence/375 sample 에서 selector `2:0,10:0` 과 current root 를 관측했다. `out/runtime_patched_selector_followup_context.json` 은 sampled event timeline 의 `2:0 -> 10:0` 이동을 target-side address-adjacent alias 로 묶고, `map1_01a` 미포함/공개 캡처 save 없음/selected-pointer producer 없음/bridge execution proof 없음 때문에 non-promoting 으로 고정한다. 정확한 follow-up pointer `0x00540540` 도 `10:0` tail offset `0x409c` 에서 opcode `0x65 -> 0x20`, descriptor `0x005400ec`, `no-fixed-advance` 로 멈추며 exact bridge/source-map/current-root ref 가 없다. `out/runtime_selected_pointer_patched_public_selector_2_0_active_order_poll.json` 은 같은 diagnostic 경로에서 active order count/order 가 375 sample 내내 `0x01/[0x00]` 으로 고정됨을 보여주지만 constructed save 상태라 route proof 가 아니다. 다만 이 근거는 저장 파일 경로와 public/constructed save load path 일부가 확인됐다는 뜻일 뿐이고, standalone synthetic selector 도 non-promoting 이며 실제 route selector `2:0` 캡처 save 또는 strict route trigger 증거가 아니므로 route promotion 은 blocked 로 유지한다.
- `out/runtime_patched_selector_exit_candidates_poll.json` 은 top `18,0`, bottom `16,47`, left `3,14`, right `34,19` 네 출구 좌표로 public-base selector `2:0` save 를 각각 구성해 polling 했다. left 만 selector `2:0` 을 관측했고 top/bottom/right 는 `50:0` 에 머물렀으며, branch-state/opcode24 watch 는 모두 `0x00` 이라 diagnostic-only 로 남긴다.
- `out/runtime_patched_selector_left_stability_poll.json` 은 left `3,14` constructed save 를 `load-only`, `load-left`, `load-right` 세 sequence 로 다시 분리해 679 sample 을 수집했다. `load-only`/`load-left` 는 `50:0` 에 머물렀고 `load-right` 만 `2:0 -> 10:0` 을 관측했으며 opcode24 watch 는 모두 `0x00` 이라, left route hit 도 constructed diagnostic 으로만 취급한다. 이후 `out/runtime_patched_selector_left_stability_recheck_poll.json` 은 같은 sequence 를 selector-only 로 재검증해 680 sample 모두 `50:0`/route hit 0회였고, `out/runtime_patched_selector_left_active_order_poll.json` 도 active-order watch 포함 679 sample 모두 `50:0`, active count `0x00`, slot0 descriptor runtime `0x00266004`, runtime slot-base table0 `0x00000000`, route hit 0회였다. 따라서 이 left route hit 는 재현되지 않는 constructed calibration 으로 낮추고 promotion 근거에서 제외한다.
- `out/runtime_selected_pointer_patched_public_selector_2_0_active_order_poll.json` 의 확장 watch 는 route-reaching row 기준 active order count/order 가 210 sample 내내 `0x01/[0x00]` 이고, `0x0059db30[0]` slot-base table 이 runtime `0x00177750`/static `0x00457750`, `0x0059dd70..78` object table 이 static `0x0055be00,0x0055d2f8,0x0055d5d4` 임을 보여준다. 이 역시 constructed save diagnostic 이라 normal route proof 로 승격하지 않는다.
- 같은 route-reaching diagnostic row 에서 opcode24 watch 도 `0x0059e348` mode1 source, `0x0059e34d` runtime flag, `0x0059e33e` current object index 를 모두 210 sample 내내 `0x00` 으로 유지한다. 따라서 constructed selector `2:0` load 는 opcode24 mode1 producer/dispatch proof 로도 승격하지 않으며, normal route 의 producer trace 또는 strict hotspot 이 여전히 필요하다.
- `tools/parse_savedata.py` 와 `tools/scan_savedata_slots.py` 는 save offset `0x0010`/`0x0011` 의 active descriptor count/order 후보도 보고해서 opcode `0x20` runtime descriptor/order 증거 수집에 바로 쓸 수 있다.
- `tools/probe_exe_scene_tables.py` 로 `Hwanse2.exe` 의 장면 로딩 레코드에서 맵별 주변 타일셋을 텍스트/JSON 으로 확인 가능.
- `tools/probe_exe_code_refs.py` 로 `.text` 안의 VA 참조를 스캔 가능. 현재 대표 `scene_events` record 주소는 직접 코드 참조가 없어 상위 테이블/인덱스 경유로 보인다.
- `tools/extract_scene_events.py` 로 `Hwanse2.exe` 장면 레코드의 좌표 테이블 후보를 `out/scene_events.json` 으로 추출 가능.
- `tools/extract_scene_events.py` 는 좌표 후보를 `0` sentinel 까지 raw point table 로 읽고, 맵 내부 좌표만 overlay용 `points` 로 분리한다.
- `tools/dump_scene_event_record.py` 로 특정 event record 의 raw/in-bounds 좌표, tail dword, pointer block 을 덤프 가능.
- `tools/probe_exe_pointer_refs.py` 로 `.text`/`.rdata`/`.data` 안에서 특정 VA/range 를 가리키는 포인터 역참조를 찾을 수 있다.
- `extract_scene_events.py` 는 event record 의 `record + 0x0c` dispatch 주소를 가리키는 `.data` 역참조를 `eventDispatchRefs` 로 저장한다.
- dispatch 역참조 직전 조건 블록의 payload 에서 `map_*.cns`, `map[0-9]*.cns`, `cara_*.cns` 같은 리소스 문자열을 `conditionLinkedStrings` 로 추출한다. `out/scene_dispatch_summary.md` 와 웹 HUD/inspect 패널에서 장면 로드 후보를 바로 확인 가능.
- `tools/summarize_scene_links.py` 와 `out/scene_links_summary.md`/`.json`/`.js` 로 condition payload 기반 필드 맵 연결 후보를 집계한다. 예: `map1_02b -> map1_01a`, `map5_38i -> map5_11i/map5_12i/...`, `map8_32q -> map8_19p..map8_31p`.
- `web/index.html` 은 `out/scene_links.js` 를 읽어 현재 맵에 연결 후보가 있을 때 상단 `linked maps` 선택 목록을 표시한다. 전환 좌표/스폰 확정값이 아니라 장면 리소스 연결 후보를 빠르게 비교하기 위한 디버그 UI다.
- `tools/summarize_event_transitions.py` 와 `out/event_transitions.json`/`.js` 로 hotspot 좌표와 field map 링크를 묶은 전환 후보를 생성한다. 각 후보에는 condition block 별 대상 맵(`conditionChoices`)이 포함되어, 여러 field map 링크가 한 record 에 섞인 경우도 구분해 볼 수 있다. 웹 런타임은 이 JS를 읽어 hotspot에서 `Enter`/`Space` 전환을 처리한다.
- `tools/summarize_tileset_candidates.py` 와 `out/map_tileset_candidates.md` 로 현재 선택 타일셋, 파일명 접미사 후보, EXE scene 후보, condition payload 후보를 나란히 비교 가능.
- 오래된 맵 렌더 후보/감사 갤러리는 기본 빌드와 검증에서 제외했다. 현재 렌더 기준 확인은 `web/map_review.html`, `web/map_gallery.html`, `web/battle_background_review.html` 을 사용한다.
- `web/map_review.html` 에서 렌더 후보를 accept/reject 로 표시하고 export 한 JSON 은 `tools/map_render_reviews.py --merge exported.json --write-src` 로 `data/map_render_reviews.json` 에 검증 병합 가능.
- `web/map_review.html` 은 확정된 CNS map assembly 를 확인하는 화면으로 남긴다. `tools/map_render_reviews.py --merge ... --dry-run` 은 브라우저 export 리뷰 JSON 을 검증하고, `--write-src` 를 붙이면 `data/map_render_reviews.json` 에 병합한다.
- `tools/map_render_reviews.py --merge ... --dry-run` 은 `page20x6quad_zero` 같은 비기본 `tileIndexMode` 리뷰 키도 검증한다. 예를 들어 `map2_15j|layer0|map_j1,map_j2|page20x6quad_zero` accepted patch 는 dry-run 에서 accepted maps 17 -> 18 로 요약되고, key 와 payload 의 `tileIndexMode` 가 다르면 즉시 실패한다.
- `data/map_layout_reviews.json` 은 CNS body 가 `layer0` block 뒤 `layer1` flag/occlusion block 으로 저장된다는 확정 리뷰를 보존한다. `tools/map_layout_reviews.py` 는 `out/map_layout_reviews.json`/`.js`/`.md` 만 내보낸다.
- 충돌/통행 확인은 후보 갤러리가 아니라 `web/map_review.html` 의 collision/occlusion overlay 로 검증한다.
- `tools/render_tileset_usage_gallery.py` 와 `out/tile_usage/*_usage.png` 로 자주 쓰이는 타일셋 tile ID, 사용 횟수, 실제 그래픽을 같이 확인 가능. 충돌/통행 후보를 tile ID 단위로 좁히기 위한 근거 자료다.
- 빌드는 모든 1층 필드 타일셋에 대해 `out/tile_usage/*_usage.png` 를 생성한다. coverage 0%인 다음 타일셋을 바로 열어 pass/block seed 를 확장할 수 있다.
- 구식 `web/tile_review.html` 편집 흐름은 cleanup 이후 제거했다. 현재 충돌/통행 검토는 `web/collision_review.html` 과 `web/map_review.html` 의 overlay, 그리고 `data/tile_classes.json`/`out/tile_classes.*` 기준 데이터로만 확인한다.
- `web/game.html` 에서도 `P`/`B`/`U` 로 발밑 `layer0` tile ID 를 pass/block/clear 로 분류하던 구식 디버그 흐름은 원본 충돌표가 아니므로 active UX 로 승격하지 않는다.
- `data/tile_classes.json` 은 확정된 tile pass/block 분류의 repo 기준 파일이다. 빌드가 `out/tile_classes.json`/`.js` 로 내보내며, 웹 런타임은 기준 분류와 브라우저 로컬 분류를 병합해 적용한다. 같은 `layer0` tile ID 가 통과/막힘 양쪽 문맥에서 쓰이는 경우를 위해 `passPairs`/`blockPairs` 의 `[layer0, layer1]` 조합 분류도 지원한다.
- `tools/tile_classes.py --merge exported.json --write-src` 로 브라우저 export 분류를 `data/tile_classes.json` 에 검증 병합할 수 있다. patch 쪽 판정이 우선하며 기존 pass/block 및 passPairs/blockPairs overlap 은 제거한다. 병합 시 타일셋 이미지 범위를 벗어난 tile ID 는 거부한다.
- fallback 승격 도구는 cleanup 이후 제거했다. 승격 결과는 `data/tile_classes.json` 의 명시 `pass`/`block` 및 `passPairs`/`blockPairs` 로 남기며, 이전 `promoted_tile_*_fallbacks.json` patch 산출물은 active 표면에서 재생성하지 않는다.
- 현재 기준 분류표에는 `--min-count 1` pair 승격 결과가 반영되어 `passPairs` 816개, `blockPairs` 64개가 들어 있고, 맵별 tile class gap 은 1090행/115맵까지 줄었다. 남은 `mixed` 행은 수동 맵 문맥 또는 브라우저 export 병합으로만 다룬다.
- 현재 기준 분류표에는 16개 1층 필드 타일셋 전체(`map_a1`-`map_l1`, `map_n1`-`map_q1`)의 시각적으로 확실한 바닥/벽 seed 를 포함했다. 이 값은 원본 충돌표가 아니라 웹에서 검증하며 확장할 후보 데이터다.
- 웹 런타임의 기본 collision 후보는 `local tile class + layer0 fallback` 다. 분류된 타일과 fallback 추정 타일은 collision overlay 에서 색이 다르게 보여, 아직 보정이 필요한 타일을 구분할 수 있다. 기존 `layer1 == 0` 기반 fallback 은 `local tile class + layer1 fallback` 후보로 남겨 비교한다.
- `out/tile_class_coverage.json` 은 맵별 tile class 분류 coverage 와 fallback 비율을 보여준다. `out/tile_class_gaps.md`/`.json` 은 타일셋별 미분류 tile ID 를 사용량 순으로 보여줘 다음 pass/block 보정 대상을 정한다. `fallback=mixed` 행은 같은 layer0 tile ID 가 현재 fallback pass/block 양쪽으로 쓰이는 후보라 맵 문맥 확인 후 `Shift+P`/`Shift+B` 조합 분류를 우선 적용한다. `out/tile_class_gap_galleries.md` 는 같은 미분류 타일을 PNG 갤러리로 묶어 실제 그래픽을 빠르게 확인하게 한다.
- `out/collision_fallback_delta.json` 은 현재 `layer0 > 0` fallback 이 이전 `layer1 == 0` fallback 대비 맵별로 몇 칸을 새로 통과 처리하는지 보존한다. HTML 표면은 cleanup 이후 기본 산출물에서 제외했고, 필요할 때 `tools/summarize_collision_fallback_delta.py --html-out ...` 로 명시 생성한다.
- `out/map_tile_class_gaps.md`/`.json` 은 맵별 미분류 tile ID 와 샘플 좌표를 보여준다. 각 row 의 `components` 는 같은 `layer0/layer1` 조합이 붙어 있는 좌표를 영역 단위로 묶은 검토 링크이며, 샘플 좌표 링크와 함께 `focusTile`, collision overlay, overview 를 켠 게임 화면으로 바로 이동한다.
- `tools/probe_tile_attribute_tables.py` 와 `out/tile_attribute_candidates.md`/`.json` 으로 EXE 안의 480-entry 타일 속성표 후보를 스캔 가능. 현재 후보는 다수 있으나 직접 `.text` 참조가 붙은 저값 480-entry 표는 확인되지 않아, 실제 충돌 데이터가 단순 정적 타일 플래그표가 아닐 가능성이 있다.
- `tools/dump_exe_data_table.py` 로 코드 참조 테이블을 dword 단위로 덤프 가능. `out/table_004dc514.md`, `out/table_004dda94.md`, `out/table_004de900.md` 를 확인한 결과 `0x004dda94` 는 비트마스크 선택으로 객체 `+0xb0` 에 8개 포인터 중 하나를 설정한 뒤 `0x41b66d` 를 호출하는 루틴에서 쓰이며, 현재 근거로는 정적 맵 충돌표가 아니다.
- `tools/probe_scene_coordinate_candidates.py` 로 sentinel 패턴에 한정하지 않고 장면 레코드 내부 좌표형 포인터 후보를 넓게 스캔 가능. `out/scene_coordinate_candidates.json`/`.md` 는 현재 175개 레코드를 잡지만, 대부분 반복 좌표 테이블 또는 스크립트/오브젝트 인자 후보라 실제 전환 좌표로 확정하지 않는다.
- `out/transition_extraction_gaps.json` 은 broad 좌표 후보 중 strict event transition 으로 승격되지 않은 record 를 보여준다. broad 스캐너는 다음 맵 레코드 경계를 넘지 않도록 제한되어, `map1_01a@0x005032d8` 처럼 뒤따르는 `map1_02b` 이벤트 테이블을 잘못 물고 나온 오탐은 생성하지 않는다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `web/game.html?events=1` 에서 추출된 장면 좌표 후보를 맵 위에 오버레이로 확인 가능 (`H` 키로 토글).
- `web/game.html?collision=1` 또는 `C` 키로 현재 통행 판정 오버레이와 발밑 `layer0/layer1` 타일 ID 를 확인 가능. 기본 후보는 `local tile class + layer0 fallback` 이며, 상단 collision 드롭다운 또는 `V` 키로 `local tile class + layer1 fallback`, `darkTerrainCandidate`, `terrainCandidate`, `walkCandidate`, `layer0`, `layer0NonEmpty`, `layer1Empty`, `layer1`, `both`, `either`, `none` 후보를 비교 가능. `terrainBlockedTiles` 밝기 기반 후보는 `map1_02b` 에서 바위벽/어두운 길을 안정적으로 구분하지 못해 진단용으로만 둔다.
- collision/event 디버그 표시 중에는 현재 맵의 렌더 리뷰 링크도 함께 표시된다. accepted 맵은 accepted visual 필터로 열리고, 미검수 맵은 같은 타일셋 계열의 accepted 대표 visual 필터로 열린다.
- 일반 게임 화면은 accepted 렌더 리뷰가 있으면 해당 visual/tile 조합을 쓰고, accepted layout 리뷰가 있으면 해당 CNS body layout 도 적용한다. accepted 렌더가 없는 맵은 같은 타일셋 계열의 accepted 대표 visual 을 쓰고, 그래도 없을 때만 `layer1UnderSceneTilesets` 로 fallback 한다. 기본 tile index/layout 은 `row40 0-based` + `planar_layers` 다. `layer0 only` 는 일반 화면의 trusted visual 후보로 남겨 즉시 비교할 수 있고, trusted visual 은 `?visualMode=layer0` 처럼 URL 로도 고정할 수 있다. `web/game.html?debugRender=1&map=map7_11k&visualMode=layer1UnderSceneTilesets&tilesets=map_k1,map_k2` 처럼 `tilesets` 쿼리로 후보 타일셋 조합을 그대로 열어볼 수 있으며, `web/map_review.html` 의 각 후보에는 이 게임 링크가 붙는다. `layer1` 단독, `row40 1-based`, 대체 tileset variant, CNS body layout 비교가 필요하면 `debugRender=1` 로 열어 상단 variant/visual/tile index/layout 드롭다운 또는 `R`/`T`/`L` 키로 비교한다. `debugRender=1&layoutMode=...` 쿼리는 accepted layout 보다 우선하는 수동 비교용이다.
- `web/game.html?map=map5_38i&events=1` 처럼 `map` 쿼리나 검토용 쿼리(`overview`, `collision`, `events`, `startTile`, `focusTile`, `debugRender`)가 있으면 타이틀을 거치지 않고 해당 맵 화면에서 바로 시작한다. 발밑 tile/hotspot record 는 디버그 HUD 로 확인 가능.
- 쿼리 없이 타이틀에서 `Enter`/`Space` 를 누르면 현재 confirmed 전환을 바로 테스트할 수 있도록 `map1_02b` 의 `11,12` 에서 시작한다. 쿼리로 특정 맵을 연 경우에는 해당 맵 시작을 우선한다.
- `web/game.html?map=map1_02b&startTile=11,11` 처럼 `startTile=x,y` 쿼리로 시작 타일을 지정 가능. 런타임은 캐릭터 발밑 기준 `footTile()` 과 `playerPositionForTile()` 의 역변환을 맞춰 `startTile` 이 내부 발밑 좌표와 어긋나지 않게 한다.
- `web/game.html?map=map1_02b&overview=1`, 실행 중 `F` 키, 메뉴 `전체 지도`, 또는 우측 `전체` 버튼으로 현재 맵 전체를 플레이 영역 안에 맞춰 볼 수 있다. 우측 버튼은 `overview=1` URL 도 동기화해 모바일 브라우저에서 메뉴/키보드 없이 전체 맵 확인 링크를 만들 수 있다. 전체 보기에서도 collision/event/focus overlay 와 플레이어 위치 표시가 유지되며, 맵을 클릭하면 해당 타일을 focus 로 잡고 가장 가까운 통행 가능 위치로 이동한 뒤 일반 카메라 화면으로 돌아온다. 전체 보기로 열린 검토 링크에서도 방향키/WASD 로 이동을 시작하면 일반 카메라 추적 화면으로 자동 전환된다. 기본 플레이어는 아타호 `cara_at1` 스프라이트를 쓰고, 이동은 타일 단위 0.192초 스텝마다 재생되고, 방향별 5개 프레임 중 0번은 정지 포즈라 이동 중에는 1-4번만 사용한다. 방향키/WASD 를 누르고 있으면 다음 타일 이동을 바로 이어서 시작한다. 입력 방향이 벽에 막히면 수직 입력은 좌/우, 수평 입력은 상/하 보조축으로 미끄러지며, 한쪽 보조 방향이 막히면 선호 방향을 뒤집어 좁은 2칸 구간에서 자동 왕복한다. `moveMs=80..300` 쿼리로 한 타일 이동 시간을 조정할 수 있다. `out/runtime_timing.html` 은 원본 EXE 의 `GetTickCount` 메인 루프가 `0x30`ms(48ms) tick 을 쓰고 catch-up 을 3 tick 으로 제한함을 고정하며, 웹 기본값은 이동 프레임 4개 * 48ms 로 맞춘 값이다. `out/runtime_movement.html` 은 `0x00411476` per-frame update 가 입력 mask update `0x00422d74`, active object callback `0x00435c04`, object script/timer `0x00432ff0` 를 호출하고, draw prep `0x00424a2a` 가 object `+0xe8/+0xea` tile 좌표와 camera/save tile `0x004576dc/0x004576de` 를 16px 단위로 투영함을 고정한다. 같은 산출물은 `0x0043022d` actor controller, `0x004319f8` collision helper, `0x0058d7d0`/`0x0058d7ce` collision flag table, helper 의 방향 latch `0x05..0x08`, blocked fallback `0x01..0x04`, 방향별 flag bit `down=0x02/up=0x01/left=0x04/right=0x08`, actor-overlap collision response, `0x0042449c` map loader 의 CNS layer0->`0x00595af0` 및 CNS layer1->`0x0058d7d0` 복사, `0x00416ce2` draw helper 의 `+0x28` frame selector/source-rect/`+0x30/+0x34` sprite offset 소비, object script/timer `0x00432ff0` 의 `+0x62`/`+0x64` 및 opcode `0x21` handler `0x004044bd` frame selector path, party actor descriptor table `0x00442d95`, opcode `0x20` handler `0x0040448a` 의 `+0x64` frame script pointer 초기화, opcode `0x18` handler `0x0040408f` 의 `18 a0 64 68 <state-table-va>` 명령이 `object+0x68` 로 `+0x64` frame script 를 고르는 경로, `cara_at1.cns`/`cara_rs1.cns`/`cara_sm1.cns` state 1..8 의 opcode `0x21` selector loop, 웹 구현의 `ORIGINAL_FRAME_MS * 4` = 192ms 이동 스텝, 5프레임 보행 frame constants, 8-command selector cadence, browser 48ms sub-tile interpolation, `collisionMode=originalLayer1Flags` 기본 충돌 모드, 기본 동료 actor overlap 충돌과 `actorCollision=0` opt-out, `tileClassLayer0` 로컬 검토 fallback, wall-slide fallback 이 실제 `web/index.html` 에 남아 있는지도 검증한다. 따라서 16px tile grid, held-key mask 소비, input-driven actor tile mutation, party actor draw projection from tile/trail entries, party actor `+0x68` -> `+0x64` frame-script table -> `+0x28` selector sequence, `+0x28` frame selector/source-rect 소비와 opcode `0x21` script/timer 갱신 경로, browser 48ms sub-tile interpolation, original collision flag tests, directional latch fallback cases, actor-overlap collision response, CNS layer1 collision flag grid, 기본 동료 actor-overlap 모델, 웹 source-rect selector mapping, exact 8-command selector cadence 까지는 원본/브라우저 근거가 생겼지만, original actor interpolation timing 과 full non-party object-list parity 는 아직 필요하다. 스마슈/린샹 스프라이트는 `party_smash`/`party_rinshan` 리소스로 동료 표시에서 쓰며, savedat 가 없을 때는 메뉴의 `동료 ...` 항목이나 `party=rinshan,smash` 쿼리로 표시 구성을 순환/고정한다. savedat 를 로드하면 저장 데이터의 캐릭터 level 기준 동료 구성이 우선한다. `spriteDebug=1` 쿼리나 `Z` 키는 현재 방향의 idle+8-command selector cadence, source rect, 마지막 이동키를 화면에 띄운다. `out/character_sprite_frames.html` 은 아타호/스마슈/린샹의 48x64 보행 프레임을 잘라 보여주는 리뷰 페이지다. `out/character_sprite_frames.json` 은 방향별 source rect 와 비배경 bbox 를 기록한다. 기본 플레이/overview 화면은 맵 선택만 남기고, 충돌 후보는 `collision=1`/`C`, 이벤트/전환 후보는 `events=1`/`H`, 렌더·타일 인덱스·layout 후보는 `debugRender=1` 에서만 드롭다운을 표시한다. 도구 패널의 맵 선택에는 검색 필터가 있어 174개 맵 목록을 이름/scene id/타일셋 단서로 좁힐 수 있고, 현재 맵은 필터에 맞지 않아도 선택 상태를 유지한다.
- 2026-06-08 `map3_09a` 런타임 표면 검증 보강: `tools/verify_map3_runtime_browser.py` 는 8013 기준 WebKit에서 `map3_09a@76,18` 을 열어 `out/maps_runtime_chunks/map3_09a.js` lazy chunk, accepted `layer1UnderSceneTilesets/row40_zero` 렌더, accepted `planar_layers` layout, `originalLayer1Flags` 충돌 모드, 오른쪽 한 칸 이동 WLK step, 왼쪽 hard-block bump WLK menuMove marker 를 확인한다. 산출물은 `out/map3_runtime_browser_smoke.*` 이며 원래 goal 에 명시된 `map3_09a` 통행/충돌/우선순위 런타임 표면 확인으로 기록한다. 이 검증은 normal route 승격, original object script collision, story flag proof 로 승격하지 않고 `originalRoutePromotionImplemented=False` 를 유지한다.
- `out/runtime_movement.html` 은 동료 추종용 7-slot tile/direction history ring `0x00574540`/`0x00574550`/`0x00574552`/`0x00574554` 도 고정하고, 웹의 `partyTrail` 동료 위치 이력 모델이 같은 7-slot 제한과 초기 cursor seed `0,4,1` 을 쓰는지 검증한다. 이로써 companion trail 자체, ring size, actor별 cursor seed, post-mutation leader-tile write timing, party actor draw projection from tile/trail entries, draw helper 의 `+0x28` frame selector/source-rect/offset 소비, object script/timer opcode `0x21` frame selector path, party actor descriptor 의 `+0x68` state table frame script sequence, 웹 source-rect selector mapping, exact 8-command selector cadence 는 원본 근거가 생겼지만, full non-party object-list parity 는 여전히 별도 재구성이 필요하다.
- 2026-06-09 movement projection evidence 보강: `web/index.html` 은 party render snapshot 에 `original-draw-projection-snapshot` 을 남겨 object tile fields `+0xe8/+0xea`, camera globals `0x004576dc/0x004576de`, projection bias `0x18/0x08`, fixed shift 16, projected coord fields `+0x1c/+0x20` 을 기록한다. `tools/verify_candidate_movement_browser.py` 는 8013 WebKit movement trace 에서 `projectionBias=24,8`, `fixedShift=16`, `projectionMatches=True`, `movementDeltas=start:0,0...tick4:16,0`, `stepFractions=start:0.00...tick4:1.00`, `interpolationOffsets=start:0,0...tick3:12,0` 와 start/tick projected->spriteTop/fixedPoint samples 를 확인한다. 이는 browser 48ms sub-tile interpolation 과 projection-to-draw coordinate alignment 보강이며, original actor interpolation timing, current selector `2:0` active order, non-player descriptor behavior proof 로 승격하지 않는다.
- 2026-06-09 actor interpolation 분류 보강: `out/runtime_movement.*` 는 original actor position model 을 `tile-field-snap-plus-fixed-point-draw-projection` 으로 명시하고, actor controller tile mutation VA `0x00430b5b/0x00430b74/0x00430b8d/0x00430ba6` 및 party draw projection write VA `0x0043111d/0x00431142/0x004311ec/0x0043121d` 범위에서 original sub-tile interpolation writer 를 찾지 못했음을 별도 field 로 고정한다. 웹의 `interpolationOffset` 은 `fixedPoint` 원본 projection 값을 바꾸지 않고 spriteTop 에만 더해지는 `browser-visual-overlay-not-original-proof` 로 분류된다. `tools/verify_web_assets.py` 와 completion audit 은 `originalActorSubTileInterpolationEvidenceFound=False`, `browserInterpolationOverlayDetected=True`, `browserInterpolationFixedPointPreserved=True`, `browserInterpolationOverlayNotPromotingOriginal=True` 를 요구한다. 따라서 브라우저 48ms 보간은 UX 보강으로 유지하되 원본 actor interpolation proof 나 route/current selector proof 로 승격하지 않는다.
- savedat 가 없을 때는 기존 메뉴 `동료 ...` 순환과 별도로 `동료 선택 N` 서브메뉴가 prototype 합류 흐름을 제공한다. 메인 메뉴에는 직접 `동료 합류 ...` 행을 붙이지 않고, `party-candidate` 하위 메뉴에서 린샹/스마슈를 고른다. 이 흐름은 `party-join-prototype` 진행 기록을 남기고 quick save/load 및 타이틀 `이어하기 map1_02b 11,12` 로 `members=rinshan,smash`, `label=린샹+스마슈`, `진행 목표 2`, `quickLoadText=임시 불러오기` 를 복원한다. 완료된 동료 목표를 다시 확인하면 `party-complete:map1_02b` 대화와 함께 필드 화면 `partyNoticeFeedback=party-join-completion-notice-feedback:동료 합류 완료 2/2`, `partyNoticeFeedbackRender=True`, `partyNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 남긴다. 일부 후보 대사 완료도 prototype 합류 트리거가 될 수 있어 `event-dialogue-block-003` 완독은 `prototype-dialogue-party-join` 으로 린샹을 합류시키고 저장/복원된다. 이 대사 기반 합류 marker/autosave/progress 는 partial event VM replay 요약도 함께 보존해 `vmPartial=True`, `vmRender=7`, `vmLiteral=7`, `vmSource=0x00030000` 을 남긴다. 대사 합류도 별도 완료 목표 `후보 대사 합류 완료 map1_02b` 로 노출하며, 목표 실행은 `objectiveAction=dialogue-party-join-completion-notice`, `objectiveActiveId=dialogue-party-join-complete:map1_02b:event-dialogue-block-003`, `dialoguePartyNoticeFeedback=dialogue-party-join-completion-notice-feedback:대사 동료 합류 완료 1/1`, `dialoguePartyNoticeFeedbackRender=True`, `dialoguePartyNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 남긴다. 원본 party join event/event VM/story flag 구현은 `originalEventVmRuntimeImplemented=False`/`originalPartyJoinEventImplemented=False`/`originalStoryFlagRuntimeImplemented=False` 로 유지한다.
- `out/runtime_movement.html` 은 같은 `0x00442d95` descriptor table 12행도 전수 분류한다. Rows `0..2` 는 아타호/린샹/스마슈 party walking descriptor 로 `+0x68 -> +0x64` state-table frame script 를 쓰고, rows `3..11` 은 `btl_*`/`zsa_*`/`zsl_*` battle/effect/object resource descriptor 로 `+0x68` state-table selector 와 field-map CNS ref 가 없다. `out/non_party_descriptor_asset_links.html` 은 rows `3..11` 의 linked CNS 10개가 모두 decoded PNG/legacy aggregate workbench/EXE resource descriptor coverage 를 갖는지 묶는다. Runtime surface 는 `btl_at`/`btl_rs`/`btl_sm` direct battle party sprite asset 3개, `btl_etc` browser-local battle hit/effect prototype 1개, `zsa_saru`/`zsl_yoi`/`zsa_mi`/`zsa_kika` battle sprite-only candidate 4개, `zsa_iwa` field object overlay candidate 1개, `btl_efc` legacy aggregate workbench-only battle/effect sprite 1개로 분리된다. 새 scene-anchor 대조는 scene event 에 직접 연결된 z*.cns 7개와 descriptor row 의 z* 5개를 따로 비교해, descriptor z* 중 field scene anchor 가 있는 것은 `zsa_iwa.cns` 하나뿐이고 나머지 네 개는 battle sprite-only candidate 로 남는다는 점을 고정한다. `tools/verify_candidate_event_object_browser.py` 는 8013 WebKit에서 `map8_32q` descriptor row 10 `zsa_iwa.cns` 를 `field-object-overlay-candidate` 1개로 렌더/조사하는지 확인하고, scene event 직접 연결 z*.cns 7개 전체(`map1_02b:zjk_suz`, `map2_03l:zg_kni,zm_2,zs_rg`, `map8_18o:zs_dd`, `map8_32q:zsa_iwa`, `map9_01e:zi_ana`)가 loaded/rendered/inspected/anchors `7/7` 로 브라우저 런타임에서 열리는지도 검증한다. current selector `2:0` active order, original non-party script behavior, original field object runtime binding, original battle-effect timing, original battle-entry execution 은 모두 false 로 유지한다. 따라서 남은 movement 갭은 막연한 party frame mapping 이 아니라 non-player descriptor 의 runtime activation/order 와 scripted behavior 재구성으로 좁혀졌다.
- `out/runtime_movement.html` 은 `out/save_selector_opcode20_runtime_materializers.html` 의 active descriptor materializer 증거도 함께 인용한다. Save load 는 count/order 와 slot block 을 읽은 뒤 selector pointer 선택 전에 `0x00432323` 으로 slot descriptor pointer 를 재구성하고, 이후 add/remove 는 general handler table `0x00440538` 의 opcode `0x62`/`0x63` 경로다. Opcode `0x20` descriptor script 안의 self-mutation 경로는 제거됐지만, current selector `2:0` 의 실제 active order 는 공개 sample save 에 없어서 여전히 증명이 필요하다.
- 모바일 런타임은 화면의 비대화형 영역을 터치하고 드래그하면 나타나는 가상 조이스틱, 우하단 A 버튼, 그리고 A 버튼 옆 `☰` 메뉴 버튼을 제공한다. `☰` 버튼은 키보드 `I/Esc` 와 같은 런타임 메뉴 토글 경로를 쓰며, 기본 collapsed 화면에서 숨겨진 대사/조사/전투/전체 지도/저장 흐름도 메뉴 안에서 접근할 수 있게 한다. `tools/verify_mobile_runtime_controls.py` 는 소스/HTTP 응답의 배선을 점검하고, `xvfb-run -a python3 tools/verify_mobile_browser_controls.py --base http://127.0.0.1:8013` 은 WebKitGTK 에서 `party=rinshan,smash` 진입, canvas 터치 이동, document 터치 이동이 조이스틱 활성화/해제, 모바일 메뉴 버튼의 `False->True->False` 토글, 렌더 변화, URL 보존을 만드는지 검증한다. 같은 브라우저 검증은 `menu=1` 상태의 `동료 ...` 항목도 키 이벤트로 실행해 동료 구성 URL 동기화를 확인하고, `dialogueButton`/`battleButton` 클릭으로 대사와 전투가 실제 열리는지도 확인한다.
- `/web/` 게임 런타임은 전체 `out/maps.js` 대신 작은 `out/maps_runtime.js` 인덱스를 읽고, 실제 맵 레이어 데이터는 `out/maps_runtime_chunks/<map>.js` 에서 현재 맵만 지연 로드한다. 시작 시 모든 타일셋 PNG 를 한꺼번에 받지 않고, `title/window/player` 와 현재 맵에 필요한 타일셋만 먼저 로드하며, 맵 전환/variant/object preview 에 필요한 이미지는 `ensureImage()` 로 지연 로드한다. 전체 174맵 데이터와 모든 타일셋을 한 번에 다루는 화면은 `web/map_review.html`, `web/map_gallery.html`, `web/collision_review.html`, `out/*audit*.html` 같은 리뷰 도구 쪽에 남겨둔다.
- 이벤트 오버레이 모드의 hotspot 선택 목록으로 좌표 후보에 바로 이동 가능.
- hotspot 선택 항목에서 scene id, kind, linked object, blockKind 를 함께 확인 가능.
- hotspot 위에서 `Enter`/`Space` 로 condition payload 의 field map 링크 후보로 전환한다. 일반 플레이 화면에서는 confirmed 전환만 행동 프롬프트/실행 대상이 되고, `events=1` 디버그 오버레이를 켠 경우에만 unreviewed 후보까지 테스트할 수 있다. confirmed 전환은 원본 `activePoints` 쪽 방향으로 이동을 시도해도 실행되어, 출구 타일을 선택키로 누르는 방식과 출구 경계를 밀어 넘어가는 방식을 함께 검증한다. 여러 대상 후보가 있으면 행동 프롬프트의 현재 선택 후보로 이동하며, `[`/`]` 또는 숫자키 `1`-`9` 로 후보를 고를 수 있다. 전환 후에는 같은 타일 좌표를 임시 spawn 후보로 사용하고 `nearestStandable` 로 보정한다. 후보가 없으면 tail pointer block 상세 패널과 field map link 목록을 확인 가능.
- `tools/transition_reviews.py --merge exported.json --dry-run` 으로 브라우저에서 export 한 전환 후보 리뷰를 먼저 검증하고, `--write-src` 로 `data/transition_reviews.json` 에 병합 가능. 빌드는 `out/transition_reviews.json`/`.js`, `out/transition_review_gaps.html`, `out/transition_review_gaps.json`, `out/transition_review_gaps/<map>.html`, `out/transition_review_patches.json`, `out/transition_review_patches/*.json` 로 내보내고 웹 런타임은 기준 리뷰와 로컬 리뷰를 병합해 표시한다. scene record 의 in-bounds 좌표 테이블을 전환 trigger point 로 쓰며, `pointCountHint` 는 첫 좌표가 벽 marker 일 수 있어 메타데이터로만 보존한다. 원본 raw/in-bounds 좌표 테이블은 `out/scene_events.json` 에 함께 남긴다. condition payload 안에서 field map 문자열 바로 뒤에 붙는 target scene id 도 `conditionChoices[].targetSceneIds` 로 보존한다. 예를 들어 `map2_03l@0x00441000` 은 `map2_01c 0x0718`, `map2_13c 0x1318` 을 payload 근거로 보여준다. 현재 전환 gap HTML/JSON 은 918개 unreviewed row 를 이벤트 record 단위의 11개 record group, 목적지별 53개 target group, 좌표 영역 단위의 228개 connected component 로 묶어 보여준다. 현재 기준 리뷰는 `map1_02b@0x00503350` 의 통행 가능한 `11,12`/`11,13 -> map1_01a` 두 좌표를 spawn `11,11` 로 confirmed 처리하고, 같은 record 의 나머지 22개 좌표는 rejected 처리한다. 전환 리뷰 key 는 `source@record:x,y->target` 형식이라 같은 좌표/대상이 서로 다른 record 에서 겹쳐도 덮어쓰지 않는다. gap index 상단의 priority queue 는 아직 unreviewed 이면서 sourceStandable 인 component 만 보여주고, 목적지 수가 적은 record 를 먼저 올려 낮은 모호도의 전환부터 확인하게 한다. 웹 런타임의 `transitions` 드롭다운과 `M`/`Shift+M` 순회도 connected component 단위로 동작하고, `Ctrl+Y`/`Ctrl+X` 는 현재 component 전체를 confirmed/rejected 로 표시한다. 웹 런타임은 export 한 전환 리뷰 JSON 을 다시 import 할 때 실제 후보 key/source/좌표/target/state/record 를 검증한 뒤 localStorage 에 반영한다. 대상 맵에서 `export spawn review` 를 만들 때도 버튼과 patch 에 target scene id 를 포함한다. 맵별 page 는 overlay PNG 에 후보 tile/component 박스를 표시하고, component crop preview 와 대상 맵 preview PNG 도 함께 보여줘 source 위치와 이동 대상을 한 화면에서 비교할 수 있다. component 행의 `add confirm JSON`/`add confirm+spawn JSON` 은 sourceStandable 좌표만 confirmed patch 로 만들고, standable 좌표가 없는 component 는 `no standable confirm` 으로 비활성화한다. `add reject JSON` 은 해당 영역 전체의 리뷰 patch 를 basket 에 누적하고, `copy review basket` 으로 여러 component 리뷰를 한 번에 `web/index.html` import 또는 `tools/transition_reviews.py --merge` 에 넘길 수 있다. 같은 patch 는 `out/transition_review_patches/` 에 파일로도 생성되어 브라우저 복사 없이 dry-run/merge 대상이 된다. record group 의 target 목록, target group, component, gap row 링크는 `overview=1`, `transitionTarget=...`, `transitionRecord=...` 쿼리를 붙여 전체 맵에서 해당 target 과 record/좌표가 선택된 상태로 열린다.
- confirmed 전환 리뷰에는 선택적으로 `spawnX`/`spawnY` 를 함께 넣을 수 있다. 값이 있으면 웹 런타임은 임시 `sameTileNearestStandable` 대신 해당 target 맵 타일로 도착시키며, `tools/transition_reviews.py --merge` 와 웹 import 는 spawn 좌표가 target map bounds 안에 있는지 검증한다. gap 페이지의 `add confirm+spawn JSON` 버튼은 target spawn tile 을 `x,y` 로 입력받아 basket patch 에 포함한다. `choose spawn` 링크는 대상 맵을 `overview=1&collision=1` 로 열고 source/record 후보 정보를 넘기며, 대상 맵에서 캐릭터를 도착 타일로 이동한 뒤 `export spawn review` 버튼을 누르면 현재 발밑 타일이 `spawnX`/`spawnY` 로 들어간 confirmed patch 를 얻을 수 있다.
- 오래된 probe/실험 산출물과 탈락한 렌더 후보 갤러리는 `out/` 에서 제거했고, 현재 유지 대상은 재생성 가능한 audit/review 산출물과 사용자가 정상 기준으로 확인한 `out/collision_candidates`, `out/manual_review_map_a` 이다.
- 발밑에 confirmed 전환 후보가 있으면 이벤트 오버레이가 꺼져 있어도 하단에 `Move/Enter -> map...` 또는 `Enter -> map...` 행동 프롬프트를 표시한다. 원본 active point 방향을 알 수 있는 confirmed 후보는 이동 시도 트리거로도 실행되며, unreviewed 전환 후보는 `events=1` 디버그 오버레이를 켠 상태에서만 프롬프트와 실행 대상에 포함된다.
- `out/playable_progress.html`/`.md`/`.json` 은 confirmed 전환만 사용하는 일반 플레이 진행 그래프를 요약한다. 현재 웹 타이틀 시작 경로는 `map1_02b&startTile=11,12` 이며, confirmed 전환 기준 reachable map 은 `map1_02b`, `map1_01a` 2개다. 같은 리포트의 `Map-Exit Trial Routes` 는 `trialTransitions=mapExitCandidates` 로 geometry-only 출구 후보를 켠 실험 진행 그래프를 별도로 보여주며, `trialTransitions=routeAssist` 는 selector-only link 와 geometry-only 출구 후보를 동시에 켜서 `map1_01a -> map2_02d` 같은 막힌 route 를 웹에서 이어서 시험하게 한다. 이들은 confirmed normal route 로 승격하지 않는다. `Next Review Candidates` 는 목적지 수가 적은 record 를 먼저 두고, 통행 가능한 미검토 좌표 수와 첫 검토 링크를 함께 보여줘 다음 전환 확정 작업을 좁힌다.
- `out/save_selector_branch_state_*`, `out/event_object_branch_state_*` 리포트는 `map1_01a -> map2_02d` save-selector frontier 의 분기 상태 근거를 추적한다. 현재 `primaryBranchState` writer 는 event/object VM handler table `0x0047f1d8` 로 dispatch 되는 함수들이다. `out/save_selector_branch_state_dispatch.html` 은 dispatcher byte-check 를 고정해 `0x0041b687` 이 `context+0xb0` 의 첫 byte `0x40` 을 table-dispatch marker 로 보고, `stream+1` index 로 `call dword [index*4 + 0x0047f1d8]` 를 실행한다는 점을 확인한다. 따라서 save-selector leaf stream 안에서 low byte 가 `0x25`/`0x26`/`0x27`/`0x31` 처럼 겹치는 것은 event/object handler 실행 증거가 아니다. `out/event_object_branch_state_candidate_links.html` 기준 중간 신뢰도 후보 10개는 현재 selector/manifest index hit 0, current selector root `0x00540714..0x00543578`/leaf stream `0x00542ac0..0x00542e88`/scene record `0x00542b44..0x00542e78` range hit 0, route-map selector container hit 0 이다. 후보들은 field-map link 가 없는 `25:0` 또는 `43:0` selector/data container 에만 들어간다. `out/event_object_branch_state_block_context.json` 기준 `0x004e82xx` 후보 8개는 CP949 메뉴/목록 문자열(`기본기`, `공격기`, `도구`, `무기`, `의문의 던전` 등) 주변이고, `0x00544a35`/`0x00544e0d` 는 field-map CNS 참조가 없는 포인터 중심 selector-like 블록이다. 따라서 이 후보들은 VM 해석에는 유용하지만 현재 맵 진행 경로를 promote 할 증거가 아니다.
- `out/save_selector_selection_state.html` 은 save-selector branch-state handler 를 정리하며, helper `0x00410c90` 의 jump table `0x00410db0` case `0x00..0x0b` 를 검증한다. case `0x00` 은 `secondaryBranchState[0..1]=1` 을 만드는 predecessor fill 근거이고, opcode `0x13` handler `0x0040b696` 은 `0x0059e344` runtime byte 와 slot field `+0x4a/+0x48` 를 맞춰 `(context+0xa8)[stream+2]` 에 slot index 를 쓰는 selection opcode 로 고정했다.
- `out/save_selector_active_flag_sources.html` 은 `map1_01a -> map2_02d` 의 `0x005428bc` opcode `0x12` 가 참조하는 active-selection flag `0x00457744` 를 고정한다. EXE static byte 와 startup init routine `0x00411300` 은 이 값을 `1` 로 두며 caller 는 `0x00401928` 1건이다. 다만 이 byte 는 first save block 의 save offset `0x006c` 이기도 해서 save-load 경로에서는 덮일 수 있으므로, 실제 route 의 save/runtime 값과 이전 `selectionBuffer[0x20]` 은 여전히 증명 대상이다.
- `out/save_selector_branch_selector_equation.html` 은 `map1_01a -> map2_02d` 의 `selectionBuffer[0x20]` 조건을 `secondaryBranchState` 12칸 테이블 방정식으로 정리한다. predecessor `1:0` fill 가설을 대입하면 모든 시작 slot 이 pass slot `0`/`1` 로 수렴해 이전 `selectionBuffer[0x20]` 과 branch-state 값 자체는 주요 blocker 에서 내려오지만, 이 가설은 아직 route proof 가 아니므로 `1:0 -> 2:0` 실행/상태 보존, gate-time control-flow/base, strict source hotspot, 실제 selector `2:0` save/runtime trace 가 남는다.
- `out/save_selector_active_flag_effect.html` 은 active flag 증거를 predecessor fill 가설과 결합한다. `1:0` 이 `secondaryBranchState=[1,1,0..]` 를 남겼다면 active flag 가 `1` 이든 save/load 로 `0` 이든 모든 시작 slot 이 pass slot `0`/`1` 로 수렴한다. 따라서 이 가설 안에서는 이전 `selectionBuffer[0x20]` 자체가 주요 blocker 가 아니며, 남은 핵심은 `1:0` 실행/상태 보존, gated control path, strict `map1_01a` hotspot 이다.
- `out/save_selector_route_root_ref_context.json` 은 source-side `0:0`, target-side `1:0`, current `2:0` selector root 의 dword 참조 체인을 따로 고정한다. 세 root 모두 `selector table row -> selected root` 로 이어지는 table-only chain 이며 `.text` direct ref 는 0개, predecessor `1:0 -> 2:0` root ref 도 0개다. 따라서 `0:0`/`1:0`/`2:0` 의 주소상 인접성과 map list 병합 모양은 selector table membership 근거일 뿐 실행 순서 증명이 아니다.
- `out/save_selector_mapset_aliases.html` 은 target-side `map2_02d` map set 이 selector `1:0`, `10:0`, `17:0` 세 alias 로 반복된다는 점을 고정한다. `1:0` 은 logical predecessor 이자 공개 샘플 `flack3r_savedat2` 가 덮는 selector, `10:0` 은 current `2:0` 바로 앞 주소 root 이며 secondaryBranchState fill-shaped row 25개를 가진 selector, `17:0` 은 public sample 이 없는 추가 alias 다. current `2:0` 은 target alias set + `map1_01a` 로 설명되지만, source `0:0` + target set 은 `map1_02b` 를 과포함하므로 alias/recomposition 근거는 실행 순서나 strict hotspot proof 로 승격하지 않는다.
- `out/save_selector_target_alias_state_effects.html` 은 target-side alias `1:0`, `10:0`, `17:0` 에 current reader 의 branch-state equation 을 적용한다. modeled fill value `0x00000210` 은 `[1,1,0,0,0,0,0,0,0,0,0,0]` pass table 로 해석되고, fill proof 가 있는 `1:0` 과 `10:0` 은 실행/상태 지속이 증명된다면 모든 start slot 이 current reader `0x00542b0c` 를 통과한다. 하지만 `17:0` 은 fill proof 가 없고, 어떤 alias 가 실제 실행되는지/상태가 current `2:0` 까지 지속되는지/strict source hotspot 이 있는지 아직 증명되지 않아 promotion 은 blocked 유지다.
- `out/save_selector_target_alias_bridges.html` 은 target-side alias root 에서 bounded current root `0x00540714..0x00543578` 로 향하는 직접 dword link 를 스캔한다. public sample 이 덮는 target alias 는 `1:0` 뿐이지만 public-covered forward/data/after-fill-data alias 는 모두 0개이고, forward hit 는 전부 public sample 이 없는 address-adjacent `10:0` 에만 있다(`forwardHitPublicSampleCount=0`, `publicForwardHitCoverageStatus=uncovered-address-adjacent-only`, `targetAliasExecutionExclusionStatus=address-adjacent-alias-data-only`). `10:0` 에서 current range 로 가는 hit 는 75개지만, current root 를 직접 가리키는 1개는 current selector row selected-root metadata `0x0053f328 -> 0x00540714` 이고, 마지막 fill 뒤 tail hit 74개는 모두 data link 다. 따라서 `aliasToCurrentPromotingExactHitCount=1` 은 metadata-only 이고 promoting data hit 는 0개다. 그 74개는 pre-writer script range 65개와 leaf-table-window 9개로만 나뉘며, leaf-table hit 9개 중 route-pair descriptor index `6`/`8` hit 는 2개다. 두 route-pair descriptor 의 raw reader hit 는 0개지만 opcode `0x2c` 보정 trace 기준 corrected/effective reader hit 는 2개이고, frontier-leaf hit 는 0개다. tail pre-writer script range 의 unique target 38개를 trace 해도 current writer `0x005428bc`, reader `0x00542b0c`, `map1_01a`/`map2_02d` scene record 에 닿는 trace 는 0개다. 따라서 after-last-fill execution-like bridge, reader/scene-record data hit, promoting data hit 는 모두 0개이며, `1:0` 과 `17:0` 은 current 로 가는 forward hit 가 없으므로 alias bridge 역시 runtime leaf selection, 실행 순서/상태 지속/strict hotspot proof 로 승격하지 않는다.
- `out/save_selector_predecessor_bridge_refs.html` 은 predecessor `1:0` root `0x00478364..0x0048458c` 와 current `2:0` root `0x00540714..0x00543578` 사이의 직접 dword bridge 를 스캔한다. `1:0 -> 2:0` forward hit 는 0건이고, `2:0 -> 1:0` reverse hit 51건은 모두 predecessor fill site `0x004844d0/0x004844d8` 이전 조각을 가리킨다. 따라서 reverse hit 는 공유 script 구조로 남기고 실행 순서/상태 보존 증거로 승격하지 않는다.
- `out/save_selector_merge_bridge_matrix.json` 은 source-side `0:0`, target-side predecessor `1:0`, current `2:0` 세 selector root 사이의 direct dword bridge 를 pairwise 로 스캔한다. `0:0 -> 1:0`, `0:0 -> 2:0`, `1:0 -> 2:0` forward merge bridge 는 모두 0건이고, nonzero 인 `2:0 -> 1:0` 51건도 모두 predecessor fill site 이전을 가리키며 fill-site hit 는 0건이다. 따라서 direct data bridge 관점에서도 selector merge/control-flow proof 는 blocked 로 유지한다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_merge_execution_gap.html` 은 selector recomposition 근거를 실행 proof 와 분리해 압축한다. current `2:0` 은 `1:0 + map1_01a` 형태이고 route pair 를 포함하는 유일한 selector 이지만, exact previous pair union 은 0개, source/current bridge 는 0/0, predecessor/current forward bridge 는 0, reverse 51건은 before-fill reuse 이다. target alias 쪽 forward hit 도 public-covered `1:0` 이 아니라 address-adjacent `10:0` 에만 있고 `uncovered-address-adjacent-only`/`address-adjacent-alias-data-only` 로 분류되며, route-root ref 에서도 execution-like bridge 가 없다. 따라서 selector merge execution proof 는 false 이고 runtime/control-flow proof 또는 strict hotspot 이 나오기 전까지 gap 은 open 이다.
- `out/save_selector_merge_runtime_context.json` 은 selector merge gap 을 runtime evidence 와 한 번 더 대조한다. current `2:0` 은 merge-shaped 이지만 shape-only 이고, forward bridge 는 absent, alias public forward 는 0개/address-adjacent forward 는 `10:0` 뿐이며, reverse reuse 는 before-fill-only, selected-root execution ref 와 any runtime poll route hit 는 false 다. patched public-base `2:0` poll 은 constructed diagnostic 으로 proof 에서 제외되고 predecessor fill-site context, route-pair entry execution, strict source/hotspot 이 모두 false 라 selector merge runtime proof 는 blocked 로 남는다.
- `out/save_selector_merge_closure_context.json` 은 priority 2 selector merge 를 closure 관점으로 다시 묶는다. `2:0` 은 `1:0 + map1_01a` shape 이고 route pair 를 가진 유일한 selector 이지만 union 이 `map1_02b` 를 extra 로 포함해 shape-only-overinclusive 로 남는다. source/predecessor/current forward bridge 는 `0/0/0`, reverse reuse 는 `51/51/0` 으로 fill site 이전뿐이며, target alias forward 는 public-covered `1:0` 이 아니라 address-adjacent `10:0` data-only 다. route roots 는 table-only, selected-root real route poll 은 false, predecessor opcode10 context 도 runtime all-zero/fill match 0/proof false 이므로 `selectorMergeClosureProofFound=False` 및 `predecessorPersistenceUsableForCurrent=False` 로 고정한다.
- 같은 closure context 는 이제 predecessor persistence gap 의 `routeOrderProven=False`, `persistenceProven=False`, `selectorMergeGapOpen=True` 도 top-level 과 evidence row 로 직접 싣는다. 따라서 p2 closure JSON 만 보아도 selector merge 가 shape-only일 뿐 아니라 route-order/persistence proof 도 닫히지 않았음을 확인할 수 있다.
- `out/save_selector_predecessor_route_order.*` 도 P2 selector-merge blocker 의 source report 형식에 맞춰 `proofFound=False`, `predecessorRouteOrderProofFound=False`, `failedPredecessorRouteOrderGateIds=source-current-selector-merge-order,predecessor-branch-state-persistence,strict-source-hotspot`, `missingEvidence=3`, `evidenceRefs=4` 를 직접 싣는다. 이 ref 는 이제 `out/save_selector_predecessor_persistence_gap.*`, `out/route_investigation_queue.*`, `out/route_promotion_gate.*`, `out/route_blocker_evidence_matrix.*`, `out/completion_audit.*` 에 전파되어, selector index/progress 가 1:0->2:0 후보를 지지하더라도 confirmed source-side `0:0` 이 predecessor `1:0` 이후 current `2:0` 로 진행했다는 실행 순서와 branch-state persistence, strict source hotspot 이 모두 미증명임을 P2 next-action refs 에서 바로 추적할 수 있다.
- `out/save_selector_wrapper_execution_gap.html` 은 current selector `2:0` 의 leaf 선택/wrapper 실행 proof 를 별도 gate 로 묶는다. route-pair descriptor entry 6/8 은 opcode `0x2c` 보정 trace 기준 reader `0x00542b0c` 에 닿지만, reader-bearing wrapper `0x00542a04` 는 current root table pointer `0x005429dc` 앞의 negative entry `-12`/`0x005429ac` 이고 opcode `0x07` 은 wrapper, leaf table window, negative entry, frontier leaf `0x00542ae8`, reader 를 선택하지 않는다. 전역 leaf-table scan 도 selector table 35개/field entry 261개에서 current route-pair index 를 `-13,-12,6,8` 로 고정하고, frontier reader-bearing leaf 는 negative entry 에만 있다고 표시한다. `out/save_selector_route_pair_entry_execution_gap.html` 은 이 모순을 `corrected-trace-not-normal-selection-proof` 로 별도 분류해, reader 가 보정 non-negative trace 로는 reachable 이지만 non-negative index 로 selectable 이 아니고 정상 selected-root/wrapper/source-producer proof 가 없음을 고정한다. wrapper entry ref 는 1개뿐이며 current root entry-run ref 0, opcode `0x5a` mode0 fallthrough word 1, promoting ref 0이고, source/predecessor opcode `0x08` current root/range producer 와 opcode `0x09` current-range store 도 모두 0이다. 이번 pass 에서 wrapper gap 자체도 root table direct-ref context 를 받아 `0x005429a8..0x00542a10` table direct refs `14/0`, route-entry/route-leaf/frontier-leaf/frontier-reader text refs `0/0/0/0`, status `data-only-no-text-ref` 를 보여준다. constructed `2:0` diagnostic 의 left stability route hit 125개는 recheck 에서 0개로 재현되지 않고 active-order recheck 도 `0x00x679`/route hit 0이라 `diagnostic-only-not-reproduced` 로 wrapper proof 에서 제외한다. 그래서 current leaf selection proof, wrapper execution proof, current selector leaf execution proof 는 모두 false 로 남는다.
- 이번 p6 pass 는 selected-root/wrapper/route-pair execution gap 의 행 단위 blocker 를 상위 산출물까지 직접 전파한다. `out/route_investigation_queue.*` 는 selected-root `gateRows` 8개, route-pair `evidenceRows` 11개, route-pair entry row 2개, negative reader row 1개와 remaining proof 4개를 보존하고, priority 6 evidenceRefs 도 같은 세부 필드를 가리킨다. `out/route_promotion_gate.*` 와 `out/completion_audit.*` 도 selected-root gate row, route-pair evidence rows, wrapper evidence rows 13개를 함께 싣기 때문에 current selector leaf/wrapper execution blocker 를 summary string 이 아니라 원본 행 단위로 추적할 수 있다.
- `out/save_selector_wrapper_execution_gap.*` 도 이제 자체 `evidenceRefs=11` 을 싣는다. refs 는 leaf table/local+global context, wrapper descriptor, route-pair descriptor, opcode `0x07/0x08/0x09` scans, selected-root execution gap, current-root frontier paths, selector merge execution gap, route-pair entry execution gap 을 직접 가리키며, route queue/promotion gate/blocker matrix/completion audit/verifier 가 같은 count/path 를 강제한다.
- `out/save_selector_selected_pointer_usage.json` 은 selected pointer 전역 `0x0059de30`, selector table `0x00442d35`, source `0:0`, predecessor `1:0`, current `2:0` 의 row/root/leaf 직접 dword 참조를 EXE 전체에서 스캔한다. `0x0059de30` 은 `.text` 6건으로 런타임 choke point 가 확인되고, 그중 writer hook 은 4개(`0x004234ba` save-loader, `0x0040adb8` opcode07, `0x0040ae37` opcode09 mode0, `0x0040ae4a` opcode09 mode1), reader hook 은 2개(`0x0040add6` opcode08 zero-check, `0x0040adfe` opcode08 activator-read)다. 리포트는 handler byte-check 도 함께 고정한다. save loader 는 save byte `0x0002`/`0x0003` 으로 group/slot row 를 골라 `0x0059de30` 에 저장하고, opcode08 activator 는 `0x0059de30` 이 nonzero 일 때 현재 stream 을 stack 에 보존한 뒤 `context+0x40 = 0x0059de30` 으로 바꾼다. 따라서 가장 좁은 runtime proof point 는 `0x0040adfe` 에서 `0x0059de30 == 0x00540714` 를 잡는 것이다. current `2:0` row/root/second-level/leaf/source/target record 는 `.text` 직접 참조 0건이라 정적 근거만으로 route 를 승격하지 않는다. 이제 이 리포트도 `proofFound=False`, `selectedPointerUsageProofFound=False`, `failedSelectedPointerUsageGateIds=static-current-selector-text-ref,selected-pointer-runtime-current-root,opcode08-current-root-activation,real-selector-2-0-savedata,strict-hotspot-or-runtime-producer`, `missingEvidence=5`, `evidenceRefs=5` 를 top-level 로 싣고, route investigation queue, route promotion gate, completion audit verifier 가 같은 fields 를 강제한다. 다음 증거는 save offset `0x0002=2`, `0x0003=0` 샘플 또는 `0x0059de30 == 0x00540714` 런타임 trace 다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_xrefs.html` 은 `map1_01a -> map2_02d` selector path 의 pointer reference 를 역할별로 분리한다. current `2:0` root `0x00540714` 의 직접 ref `0x0053f328 -> 0x00540714` 는 `current-selector-row-selected-root-entry` 로 분류되어 save selector row metadata 일 뿐이고, current root non-metadata ref 는 0건이다. 따라서 이 ref 는 실행 bridge 가 아니며 `confirmed_route_blockers` 는 남은 근거를 `selected-root execution ref` 로 표시한다.
- `out/save_selector_selected_pointer_opcode_paths.json` 은 route 관련 selector root `0:0`, `1:0`, `2:0` 안의 selected-pointer opcode `0x07`/`0x08`/`0x09` 를 스캔한다. source/predecessor 쪽에는 opcode `0x08` activator 162건이 있지만, `0x07`/`0x09` 가 current `2:0` root/range 를 직접 선택하거나 저장하는 경우는 0건이다. current `2:0` 의 opcode `0x09` 6건은 모두 자기 root 내부 next-stream store 라서 source/predecessor 에서 2:0 으로 들어가는 증거가 아니다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_global_selected_pointer_paths.json` 은 selected-pointer opcode `0x07`/`0x08`/`0x09` 검사를 전체 save-selector root 로 확장한다. selector row 94개, unique root 28개에서 opcode row `0x07=3238`, `0x08=3180`, `0x09=316` 을 스캔했지만, non-current root 가 current `2:0` root/range 를 select/store/local-activate 하는 경우는 각각 `0/0/0` 이다. current `2:0` 내부 continuation 은 store/producer `6/35` 로 남지만 source/predecessor 에서 current 로 들어가는 selected-root execution ref 는 여전히 0건이므로 promotion 은 blocked 다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_selected_root_execution_gap.html` 은 selected-root execution ref 증거를 한 리포트로 묶는다. save-loader real selector `2:0` 샘플 0개, current root/second-level/frontier reader `.text` ref 0개, global opcode `0x07/0x08/0x09` non-current producer `0/0/0`, selected-pointer hook window `6/0`, current writer path `4`개 모두 내부 경로, runtime selected-pointer poll 은 base `1550` sample 에서 `8:0`, prelude `491` sample/long `1928` sample/late-start `1122` sample 에서 `8:0,50:0` 만 관측한다. selected-pointer global `.text` ref 6개의 local window 에도 current-root/source/target/map-loader/script-runner/selector-table route-specific ref 가 모두 0건이라 hook 자체는 trace target 으로만 남는다. 추가 handler-rooted bounded call graph 는 selected-pointer handler root `4`, reachable function/direct call edge `15/27` 을 보지만 route/current/record/selector/branch hit 는 `0/0/0/0/0` 이고 expected generic selected-pointer/selector-table hit 만 `6/1` 이라 `selected-pointer-handler-callgraph-generic-only-contrast` 로 고정된다. depth sensitivity `1..4` 도 proof absent/stable `True/True` 이므로 call graph 확장도 selected-root execution proof 로 승격하지 않는다. public save load 계열은 1353/1266/1263 sample 에서 route selector 미도달이고, input-path case-alias multislot load poll 1265 sample 은 selector `50:0` 만 관측했고 staged public selector/`2:0`/current root hit 는 0회다. predecessor direction sweep poll 3380 sample 도 같은 public `1:0` load path 에서 observed selector `50:0,19:1,1:0` 과 publicHit=True 를 보였지만 `2:0`/current root/route hit 는 0회이고 watch bytes 는 all-zero 다. patched public-base selector `2:0` diagnostic poll 375 sample 은 `2:0,10:0` 과 current root 를 관측했지만 constructed bytes 이므로 selected-root execution proof 에 넣지 않고 `anyPollRoute=False`/`selectedRootExecutionRefFound=False`/`promotionStatus=blocked` 로 고정한다. 같은 report 의 constructed diagnostic exclusion gate 는 active order `0x01/[0x00]`, active descriptor `0x004f867c`, follow-up `10:0@0x0053c4a4`, source 포함 false/target 포함 true, bridgeExec false, exact pointer `0x00540540`, trace stop `no-fixed-advance` 를 묶어 diagnostic 을 proof 에서 제외한다. `out/runtime_patched_selector_followup_context.json` 은 이 poll 의 sampled `2:0 -> 10:0` 이동을 별도 분류해 address-adjacent target alias/state-effect/bridge/global selected-pointer/selector-byte write/exact pointer trace 근거를 한 곳에 모으지만, `0x00540540` trace 가 descriptor `0x005400ec` 에서 멈추므로 normal route proof 가 아닌 diagnostic context 로만 취급한다.
- 2026-06-09 selected-root gap 은 이제 `out/runtime_predecessor_route_attempt_context.json` 도 직접 evidence ref 로 싣는다(`evidenceRefs=8`). 이 context 는 high-frequency/nearest/reciprocal/trail/coordinate/active-order/branch-state predecessor poll 13개 파일, 60 sequence, 59816 sample 을 묶으며 public predecessor 관측 파일 11개에도 selector `2:0`/current root hit 는 `0/0` 이다. dominant diversion 은 `19:1` 이고 diversion route evidence 는 false 라서 promotion status 는 그대로 blocked 지만, route queue/promotion gate/blocker matrix/completion audit 이 selected-root blocker 안에서 이 predecessor route-attempt 배제 근거를 직접 추적한다.
- `out/save_selector_opcode08_activation_windows.json` 은 위 opcode `0x08` activator 162건 각각의 직전 local selected-pointer producer 를 붙여 본다. source/predecessor 쪽 직전 producer 중 current `2:0` range/root 를 만드는 것은 0건이고, own-range 24건, script-scalar 107건, unreadable 31건으로 분류된다. current `2:0` 내부에서는 current-range producer 24건이 나오지만 이는 current root 안의 내부 continuation 이라 source/predecessor 에서 current 로 들어가는 증거가 아니다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_opcode08_unreadable_producers.json` 은 위 unreadable 31건을 다시 풀어, unique producer 10개 중 opcode `0x07` 계열 18건은 selected slot 이 EXE 매핑 밖이고 opcode `0x09` 계열 13건은 unsupported mode 라서 static current pointer evidence 0건임을 고정한다. 따라서 unreadable bucket 도 `2:0` 진입 증거로 승격하지 않는다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_opcode09_pointer_collisions.json` 은 selected-pointer opcode `0x09` 로 잡힌 row 23건을 real store 와 low-byte pointer collision 으로 분리한다. source/predecessor `0x09` 17건 중 12건은 자기 selector range 로 돌아가는 mode 0 store 이고, 5건은 full dword 가 `.data`/`.text` 주소인 pointer-shaped collision 이며 current-range store 는 0건이다. current `2:0` 쪽 `0x09` 6건은 모두 mode 0 내부 store 이고 unsupported mode 는 0건이다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_secondary_state_sources.json` 은 current selector root 의 `secondaryBranchState` source 를 현재 gate 기준으로 묶는다. `0x00542b0c` 이전 valid opcode `0x10` helper fill 은 0개, frontier 이후 valid fill 은 `0x00542fc4` 1개, `0x0059e360` secondary table direct indexed writer 는 0개다. 따라서 `map1_01a -> map2_02d` 는 여전히 이전 root/helper 또는 아직 추적되지 않은 VM state producer 를 요구한다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_current_state_sources.html` 은 current root 의 `primaryBranchState` fill 후보를 다시 고정한다. 유일한 before-frontier valid-looking `0x00542244` 값은 opcode `0x10` 행이 아니라 `0x00542240` opcode `0x11` 의 small-scalar branch-target operand(`secondaryBranchState[selectionBuffer[0xea]] == 1`) 로 분류되므로 promoting fill 은 0건이고, current primary state 도 이전 runtime state 상속으로 남는다.
- `out/save_selector_predecessor_persistence_gap.html` 은 `1:0 -> 2:0` 후보의 상태 보존 조건을 별도로 고정한다. selector table 에서 `1:0` 과 `2:0` 은 인접하고 중간 field-map selector 는 0개이며, current root 의 before-frontier secondary fill/activation fill/direct secondary writer 는 모두 0개다. 이 근거는 `1:0` 을 더 강한 persistence 후보로 만들지만, runtime 실행 순서와 global VM/helper reset 부재 및 strict `map1_01a` hotspot 이 아직 증명되지 않아 promotion 은 blocked 다. 이제 이 report 자체도 `proofFound=False`, `predecessorPersistenceProofFound=False`, `failedPredecessorPersistenceGateIds=source-target-selector-merge-order,global-vm-helper-reset-exclusion,strict-source-hotspot`, `missingEvidence=3`, `evidenceRefs=6` 을 싣고 P2 next-action refs/verifier 가 강제한다.
- `out/save_selector_secondary_route_overlap_candidates.html` 은 route-overlap `secondaryBranchState` fill root 4개를 selector 순서로 다시 나눈다. source-side previous `0:0` 의 secondary fill 은 0개이고, current `2:0` 보다 앞선 route-overlap fill root 는 `1:0` 1개뿐이며, current `2:0` 의 fill 1개는 frontier 이후다. `out/save_selector_secondary_fill_roots.html` 의 전역 fill-entry ref scan 도 entry ref 가 있는 root 를 1개 찾지만 그 selector 는 non-route-only `55:0` 뿐이고 route-overlap entry root 0개/predecessor `1:0` entry refs `0/0/0` 이라 static route-overlap fill-site pointer proof 로 승격하지 않는다. `10:0`/`11:0` route-overlap fill root 는 selector order 상 current 이후라 current 진입 증거가 아니므로, 남은 증명은 `1:0` 실행 순서/상태 보존과 strict source hotspot 으로 좁힌다.
- `out/save_selector_predecessor_tail_reset.html` 은 `1:0` root 내부의 post-fill reset 여부와 tail bridge 여부를 고정한다. `0x004844d8` 이후 root boundary `0x0048458c` 전까지 opcode `0x10` row 와 valid secondary fill 은 0개라, predecessor root 내부에서는 fill 이후 `secondaryBranchState` 를 다시 지우는 근거가 없다. 같은 tail 의 pointer dword 는 13개지만 모두 `.data` 쪽이고, current `2:0` root range pointer, exact current-root/frontier/current-reader/source-record/target-record ref, branch target into current route 는 모두 0개라 tail 자체도 current reader 로 이어지는 증거가 아니다. 남은 reset 증명은 root 밖 runtime/VM helper 경로다.
- `out/save_selector_secondary_reset_scope.html` 은 `secondaryBranchState` reset/write 범위를 전역 참조 기준으로 다시 좁힌다. `0x0059e360..0x0059e36b` 직접 indexed writer 는 0개이고 helper `0x00410c90` 직접 call 은 opcode `0x10` handler 내부 1건뿐이라, 현재 근거상 reset/overwrite 는 script opcode `0x10` row 로만 일어난다. current root 의 frontier 이전 valid secondary fill 0개와 `1:0` tail valid fill 0개가 함께 확인되지만, untraced bytecode path 실행 순서와 strict `map1_01a` hotspot 이 없어 promotion 은 blocked 다.
- `out/save_selector_predecessor_fill_opcode10_context.json` 은 predecessor fill fragment 를 opcode `0x10` handler 문맥에 직접 묶는다. opcode `0x10 -> 0x0040b49e` 는 `advance +4; read 0x02` 로 해석되고 helper `0x00410c90` direct call 은 handler 내부 1건뿐이다. fill fragment `0x004844d0..0x004844e0` 은 `0x10,0x00,0x10,0xc0` 네 row 로 opcode10/default/descriptor stop `2/1/1` 이지만, fill site `.text` direct ref 0, current reader `.text` direct ref 0, handler 내부 route immediate 0, root-tail branch/fallthrough-to-fill `0/0/0` 이다. bounded runtime poll 은 public predecessor `1:0` 을 7회/45400 sample 에서 보면서도 fill match 0, all-zero 7이라, opcode10 효과 자체는 설명되지만 fill fragment 실행/order proof 는 여전히 false 이고 promotion 은 blocked 다.
- `out/save_selector_secondary_global_reset_gap.html` 은 위 reset 근거를 runtime-order gap 과 분리한다. direct/global secondary writer 0개, unresolved ref 0개, helper opcode10-only, broad block-write 후보 0개, current before-frontier fill 0개, predecessor tail fill 0개로 `closedStaticResetScope=True` 이며, selector table 상 인접한 `1:0 -> 2:0` 사이의 reset window 도 `selectorOrderResetGapClosed=True` 로 닫힌다. 그래서 정적 reset 모양은 `staticResetShapeRuledOut=True` 로 따로 고정하지만, selector-table adjacency 는 runtime 실행 순서 증명이 아니고 실제 VM path before-reader 가 capture 되지 않아 `runtimeResetRiskClass=runtime-order-or-untraced-bytecode-path`, `globalResetRuledOut=False`, promotion 은 blocked 다.
- `out/save_selector_selected_root_execution_gap.html` 의 top-level rejection 은 `selected-root-no-real-selector-no-execution-ref-diagnostic-excluded` 로 고정한다. 이 분류는 real/current/route save count 0, static execution ref 0, hook self/promoting 0, save-selector slice runtime dispatch proof false, non-current opcode producer 0, runtime route hit false, constructed diagnostic excluded 를 한 객체로 묶어 `out/route_investigation_queue.*`, `out/route_promotion_gate.*`, `out/route_blocker_evidence_matrix.*`, `out/completion_audit.*` 에 전파한다.
- `out/route_promotion_gate.html` 의 runtime trace/equivalent rejection 은 `trace-unavailable-no-equivalent-selected-root-proof-diagnostic-excluded` 로 고정한다. 이 분류는 runtime trace 실행 불가, execution probe capture 불가, runtime poll route hit false, selected-root execution ref false, constructed `2:0` diagnostic excluded 를 한 객체로 묶어 `out/route_investigation_queue.*`, `out/route_blocker_evidence_matrix.*`, `out/completion_audit.*` 에도 전파한다.
- 2026-06-08 `tools/probe_runtime_trace_execution.py` 를 다시 실행해 Wine/qemu trace 가능성을 재확인했다. 현재 VM 에서는 `qemu-i386` binfmt 가 등록되어 있어도 WineDbg attach/launch 가 notepad control 에서도 실패하고, `Hwanse2.exe` virtual desktop 경로 역시 attach/watchpoint 로 이어지지 않으며, QEMU gdbstub 도 route watchpoint/breakpoint 삽입이 안정적이지 않다. `out/runtime_trace_execution_probe.*`, `out/runtime_trace_feasibility.*`, `out/selected_root_execution_external_proof_packet.*`, `out/route_promotion_external_proof_handoff.*`, `out/route_investigation_queue.*`, `out/route_promotion_gate.*`, `out/completion_audit.*` 를 갱신했고 `runtimeTraceOrEquivalent` 는 계속 blocked 다. 다음 selected-root proof 는 같은 WineDbg 재시도보다 실제 selector `2:0` captured savedat 또는 `0x0059de30 == 0x00540714` 를 잡을 수 있는 대체 runtime trace 환경이 필요하다.
- 2026-06-09 런타임 trace 재시도: 로그인/세션 상태가 복구된 뒤 다시 `tools/probe_runtime_trace_execution.py` 를 실행했지만 결과는 `canCaptureTraceNow=False` 로 유지됐다. 이번 pass 도 probe 18개, blocker 6개, failed gate `qemu-i386-wine-trace-capture`, `gdbstub-breakpoint-watchpoint-stability`, `route-watchpoint-trace-proof` 를 남겼고, qemu gdbstub connect control 은 성공하지만 relocated software breakpoint/watchpoint 시작 경로가 crash/unstable 로 끝난다. `out/runtime_trace_execution_probe.*`, `out/runtime_trace_feasibility.*`, `out/route_promotion_gate.*`, `out/route_blocker_evidence_matrix.*`, `out/selected_root_execution_external_proof_packet.*`, `out/route_promotion_external_proof_handoff.*`, `out/completion_audit.*` 를 새 probe 결과로 다시 갱신했으며 verifier 는 8013 기준 통과하지만 completion audit 은 계속 `achieved=false` 다. 따라서 다음 hard input 은 여전히 captured selector `2:0` savedat, strict `map1_01a` source/hotspot proof, 또는 안정적인 selected-root runtime trace/equivalent proof 다.
- `out/route_promotion_gate.html` 은 strict source/tile hotspot rejection 도 `selector-only-scene-list-no-strict-hotspot` 로 top-level alias 를 제공한다. 같은 객체는 candidate 4개, review/event 0, strict coordinate false, tile hotspot false, rejected incoming `map1_02b->map1_01a` center match 11개, target/direct strict event match 0, route-exit point 0, selector adjacency only, edge-trigger promotion false 를 묶어 `out/completion_audit.*` 의 blocker row gate evidence 로도 표시한다.
- `out/map1_01a_tile_hotspot_pattern_contrast.html` 은 confirmed `map1_02b -> map1_01a` hotspot 과 blocked `map1_01a -> map2_02d` 후보를 exact tile signature 로도 비교한다. current 후보 4개는 confirmed low-nibble 만 4/4로 맞지만 confirmed center-pair, low3x3, pair3x3 signature 는 모두 0/4라 tile evidence 는 passable geometry 수준에 머물고, route promotion gate 의 tile hotspot hard gate 도 이 exact signature contrast 를 직접 싣는다.
- `out/save_selector_secondary_block_writes.html` 은 `secondaryBranchState` 를 덮는 broad reset 후보를 별도로 훑는다. `0x0059e300..0x0059e36b` dword immediate scan 에서 table 에 닿을 수 있는 address-like base 는 5건이지만, direct overlap write/touch block write/full-cover block write 후보는 모두 0건이라 obvious memset/memcpy-style reset 은 제거된다. 다만 이것도 runtime execution order 나 strict `map1_01a` hotspot proof 는 아니므로 `globalResetRuledOut=False` 는 유지된다.
- `out/save_selector_predecessor_branch_state_execution_gap.html` 은 predecessor `1:0` branch-state 후보를 실행/상태 보존 관점에서 한 번 더 압축한다. fill pass, predecessor tail no-reset, static secondary reset scope, selector-order reset window 는 모두 닫혔지만, runtime execution order/bytecode path, selector merge/control-flow, strict `map1_01a` hotspot 이 여전히 열려 있어 `branchStateExecutionProofFound=False` 와 `persistencePromotable=False` 로 유지한다. 이 report 는 이제 fill-site 실행/order 리포트도 직접 포함해 local trace `0x004844d0->0x004844dc`, root-entry reach false, encoded-entry `raw-encoded-scalars-nonpromoting` raw/root-tail raw `4/4`, promoting `0`, 그리고 fill-site context poll `7/28/45400` sample, public predecessor hit `7`, current/route hit `0/0`, fill match `0`, all-zero `7`, field-entry/snapshot route 후보 `0/0`, `fillSiteExecutionContextProven=False` 를 같은 blocker row 에 싣는다. `out/runtime_selected_pointer_predecessor_progress_poll.json` 은 input-path/case-alias/public-save 조건에서 6개 sequence/1547 sample 을 추가로 폴링했고, 입력 품질은 PID/base/key-write/pressed-sequence 모두 6/6, pressed event 83개, observed key offsets `1,28,200,203,205,208` 이다. `out/runtime_selected_pointer_predecessor_direction_sweep_poll.json` 은 같은 public predecessor `1:0` 로드 조건에서 방향키 반복 8개 sequence/3380 sample 을 더 훑었고, PID/base/key-write/pressed-sequence 모두 8/8, pressed event 245개, observed key offsets `28,200,203,205,208` 이다. `out/runtime_selected_pointer_predecessor_direction_sweep_branch_state_poll.json` 은 같은 조건에서 8개 sequence/3377 sample 을 폴링해 public selector `1:0` 을 관측했고 active flag 는 `0x01` 로 고정됐지만 `secondaryBranchState[0..11]` 은 모두 `0x00` 으로 안정적이라 expected fill `[0x01,0x01,0x00...]` 는 관측되지 않았다. 새 `runtimeBranchStateSplit` 은 이 상태를 `public-predecessor-reached-fill-not-observed` 로 분리하며, 다음 증거를 fill-site 실행/order-before-reader 쪽으로 고정한다. 세 poll 모두 observed selector 가 `50:0,19:1,1:0` 또는 `19:1,1:0` 범위에 머물고 `2:0`/current root hit 는 0개이며 opcode24 watch byte 도 all-zero 또는 diagnostic-only 값으로 남음을 이 gap 에 연결한다.
- `out/runtime_selected_pointer_predecessor_nearest_exit_branch_state_poll.json` 은 public `1:0` save 의 `map2_02d` 시작 tile `(5,15)` 에서 가장 가까운 reciprocal geometry hint `map2_02d -> map1_01a` 후보 `(1,14)`/left edge 를 겨냥해 3개 sequence/1384 sample 을 폴링했다. observed selector 는 `19:1,1:0,50:0`, public predecessor hit 는 true, active flag 는 `0x01` 이지만 `secondaryBranchState[0..11]` 은 모두 `0x00` 이고 `2:0`/current root hit 는 0개다. `nearestExitRuntimeBranchStateSplit=nearest-exit-fill-not-observed` 로 분리해 closest geometry-driven runtime path 도 fill/order proof 가 아님을 고정한다.
- `out/runtime_selected_pointer_predecessor_reciprocal_exit_branch_state_poll.json` 은 같은 public `1:0` save 에서 나머지 reciprocal target-side hint 세 곳, 즉 `map2_02d` top `(46,0)`, bottom `(47,47)`, right `(95,16)` 까지 original layer1 direction-flag path 를 계산해 3개 sequence/11386 sample 을 폴링했다. observed selector 는 `50:0,19:1,1:0`, public predecessor hit 는 true, active flag 는 `0x01` 이지만 `secondaryBranchState[0..11]` 은 전부 `0x00` 이고 `2:0`/current root hit 는 0개다. `reciprocalExitRuntimeBranchStateSplit=reciprocal-exits-fill-not-observed` 로 분리해 remaining reciprocal geometry paths 도 fill/order proof 가 아님을 고정한다.
- `out/runtime_selected_pointer_predecessor_coordinate_branch_state_poll.json` 은 위 reciprocal path 를 coordinate watch 로 다시 폴링했다. 3개 sequence/11161 sample 에서 observed selector 는 `19:1,1:0,50:0`, public predecessor hit 는 true, active flag 는 `0x01`, `secondaryBranchState[0..11]` 은 전부 `0x00` 이지만, camera pair 는 `(5,15)` 또는 `(0,0)` 에 고정되고 actor object `+0xe8/+0xea` tile pair 는 목표 타일을 밟지 않았다. `coordinateRuntimeBranchStateSplit=coordinate-target-not-observed` 로 분리해, reciprocal geometry negative evidence 는 실제 목표 tile 도달 증명이 아니라 runtime position/object-source gap 이 남은 음성 근거로 취급한다.
- `out/runtime_predecessor_coordinate_source_scan.json` 은 public `1:0` save 를 `Down,Return` 으로 짧게 로드한 뒤 좌표쌍 source 를 훑는다. final selector 는 `19:1`, camera 는 `(5,15)`, active order 는 `0,2,2,3,3,0` 으로 남고, pair hit summary 는 public start `(5,15)` 의 pointer/static/trail/image hit `0/1/0/2`, observed trail `(15,26)` 의 `0/0/7/10`, reciprocal target aggregate 의 `0/0/0/118` 이다. rejection 은 `save-camera-memory-only-no-route-object-coordinate-source` 로 고정되어 public start 는 save/camera memory 쪽에만 걸리고, reciprocal target 은 image-memory scalar hit 만 있으며 route object/trail coordinate source 는 아직 없다. 따라서 현재 input-path public-save context 는 gameplay actor tile source 를 잡지 못했고, 다음 증거는 runtime gameplay object/position source 또는 real selector `2:0` save 쪽으로 좁혀졌다.
- `out/runtime_predecessor_field_entry_sequence_scan.json` 은 public `1:0` save 로드 뒤 baseline, 방향키 단독, `Return`/`space`/`z`/`Escape`, 방향키+확인/액션 조합까지 22개 follow-up sequence 를 훑었다. field-entry candidate 는 0개이며 final selector 분포는 `1:0` 12개, `50:0` 2개, `8:0` 2개, `19:1` 6개이고 camera 는 `(5,15)` 18개, `(0,0)` 4개다. 전체 85개 중간/final snapshot selector 분포도 `8:0` 10개, `1:0` 64개, `50:0` 4개, `19:1` 7개이고 snapshot route candidate 는 0개라 transient `2:0` 도 관측되지 않았다. classification 은 `start-coordinate-found-in-image-memory` 18개와 `start-coordinate-not-found-outside-camera-snapshot` 4개로 나뉘며, 어떤 sequence 도 selector `2:0` 또는 plausible nonzero object `+0xe8/+0xea` tile 을 만들지 못했다. 이 raw scan 자체도 이제 `proofFound=False`, `predecessorFieldEntryProofFound=False`, `failedPredecessorFieldEntryGateIds=field-entry-input-sequence,selector-2-0-snapshot,route-relevant-runtime-object-tile,selected-root-execution-proof`, `missingEvidence=4`, `evidenceRefs=4` 를 싣는다. 따라서 현재 자동 input-path 는 public predecessor 위치를 더 안정적으로 유지하지만, 원본 field gameplay 진입/route proof 는 아니며 UI sequence 증명 없이 reciprocal movement poll 을 normal route evidence 로 쓰지 않는다.
- 2026-06-07 재실행한 `out/runtime_selected_pointer_predecessor_trail_start_branch_state_poll.json` 은 coordinate source scan 에서 반복된 party trail ring `(15,26)` 을 시작점 후보로 삼아 `map2_02d -> map1_01a` reciprocal hint 4개를 다시 폴링했다. 4개 sequence/10928 sample 에서 observed selector 는 `19:1,1:0`, public predecessor hit 는 true, pressed event 는 404개였고, trail start 는 7개 ring slot 모두에서 관측되며 일부 path 는 trail/camera movement 를 보였지만 actor object `+0xe8/+0xea` 는 계속 `(0,0)` 이며 target tile 은 actor/trail 로 관측되지 않았다. `secondaryBranchState[0..11]` 은 전부 `0x00`, `2:0`/current root hit 는 0개라 `trail-start-movement-without-target` diagnostic 으로만 남기고 route promotion 은 blocked 로 유지한다.
- `out/runtime_selected_pointer_predecessor_trail_left_overrun_branch_state_poll.json` 은 위 trail-start left reciprocal path 에서 edge target `(1,14)` 도달 뒤 바깥쪽 `Left` overrun 을 3개 변형으로 추가했다. 3개 sequence/4290 sample 에서 camera 는 한 변형에서 `(1,14)` 를 관측했지만 actor/trail target 과 outside `(0,14)` 는 관측되지 않았고 selector 는 `19:1,1:0,50:0`, `2:0`/current root 는 0개이며 branch-state 는 여전히 all-zero 다. 따라서 runtime movement source 는 camera/trail 쪽으로 일부 확인됐지만, left reciprocal edge overrun 도 fill/order proof 나 normal route transition proof 로 승격하지 않는다.
- `out/save_selector_predecessor_fill_execution_order_gap.html` 은 그 다음 blocker 를 fill-site 실행 순서로 고정한다. `0x004844d0` local trace 는 `0x004844d0`/`0x004844d8` 두 fill opcode 를 모두 포함하지만 `0x004844dc` descriptor boundary 에서 `no-fixed-advance` 로 멈추며 current reader `0x00542b0c` 에 닿지 않는다. predecessor root entry `0x00478364` 에서 bounded fixed traversal 을 해도 fill site 는 닿지 않고 `0x004783e0` 에서 멈추며, fill site direct dword refs 도 0개다. root-tail branch audit 은 branch-capable row 591개를 `before-root-tail/inside-root-tail/mapped-.data/unmapped = 262/80/111/138` 로 분류했고 target section 은 `.data/.text/unmapped = 221/3/367` 이며 fill fragment/current reader branch 는 `0/0`, fixed fallthrough-to-fill 도 0이다. 새 multi-hop root-tail branch closure 도 12352 node/7249 edge 에서 branch seed 591개를 따라가지만 fill/current-reader reach `0/0` 이며 `branch-closure-no-fill-or-current-reader` 로 닫힌다. closure 밖 successor 512개도 `before-root-tail/inside-root-tail/mapped-.data/unmapped = 262/1/111/138`, section `.data/.text/unmapped = 142/3/367` 로 분류되어 fill/current-reader edge 후보가 아님을 보존한다. fill-fragment 를 가리키는 dword/root-branch target 은 0개이고, byte/word/relative encoded-entry scan 은 raw scalar coincidence 4개를 찾지만 모두 root-tail 안의 non-promoting 값이며 branch-attached 0개, modeled control-flow 0개, promoting 0개라 `raw-encoded-scalars-nonpromoting` 으로 고정된다. 추가 raw-scalar rejection scan 은 이 4개 모두를 fixed advance 없음/branch jump 없음/branch-attached 0/scalar-only 4개로 분류해 `scalar-only-no-branch-or-fixed-advance` 로 닫는다. 두 stop 은 각각 low byte `0xd0 -> 0x00440a9c`, `0xc0 -> 0x00440c5c` `.data` descriptor row 로 해석되고 shared opcode set 은 `0xc7,0xca,0xcd,0xd0,0xd3,0xd6,0xd9` 및 `0xc0,0xf5` 이지만, 이 descriptor-boundary 증거는 control-flow proof 로 승격하지 않는다. 같은 low byte 를 raw generic table 로 보면 `0xd0 -> 0x0040f02a`, `0xc0 -> 0x0040ec00` `.text` handler 로 떨어지고, generic dispatcher `0x0040234c` 는 u8 index 이므로 두 predecessor slice stop 은 generic-byte reachable 0건/테이블-base switch 필요 2건이다. 이번 pass 는 direct/dynamic indexed dispatch 116행에 대해 `0x00440538 + 0x1e8 == 0x00440720` table-base 산술 후보도 훑었고 후보 0건으로 닫는다. `0x0040234c` 는 `generic-table-immediate-only` 이며 주변에 general table immediate 1건만 있고 save-selector table/direct slice-delta immediate 는 0건이다. bounded raw generic handler window 도 추가로 닫았다. `0x0040f02a..0x0040f1f4` 및 `0x0040ec00..0x0040ee14` 에서 route/fill/current immediate 는 `0/0/0`, selected-pointer/branch-state immediate 는 `0/0`, rel32 call byte-scan 9건 중 `.text` mapped call 은 `0x00416c77`, `0x004173db` 2건이고 나머지 7건은 unmapped target 이다. mapped one-hop callee window `0x00416c77..0x00416ce2`, `0x004173db..0x00417426` 도 route/fill/current immediate `0/0/0`, selected-pointer/branch-state immediate `0/0`, route/fill direct transfer hit `0/0` 이라 `raw-generic-handlers-nonroute-contrast` 로 고정된다. 이어서 raw generic handler 두 곳에서 시작하는 bounded direct-call graph 도 depth 3 기준 reachable function/direct call edge `4/10`, mapped/text call edge `2/2`, route/fill/current immediate `0/0/0`, selected-pointer/branch-state immediate `0/0`, route/fill transfer `0/0`, proof `False` 로 닫혔다. 이번 pass 에서 depth sensitivity 를 max depth `1..6` 으로 확장했고 각 depth 가 function/edge `4/10` 으로 안정적이며 proof absent/stable `True/True` 라 raw generic callgraph 역시 `raw-generic-callgraph-nonroute-contrast` 로 전파된다. 따라서 predecessor descriptor boundary 자체도 `0x00440720` save-selector slice runtime dispatch proof 가 없는 한 static slice model evidence 로만 유지하고, raw generic 대안도 missing bridge 를 제공하지 않는다. public predecessor path 에서는 selector `1:0` 은 관측됐지만 expected runtime fill 은 관측되지 않았고, predecessor->current forward bridge 와 route order proof 도 없으므로 `proofFound=False`, promotion 은 blocked 다.
- `out/save_selector_predecessor_descriptor_bridge_gap.html` 은 위 두 stop 의 descriptor pointer closure 가 실행 bridge 를 제공하는지 따로 확인한다. `0x004783e0 -> 0x00440a9c` root-stop descriptor closure 는 949 node/4316 edge 의 complete bounded closure 안에서 c0 fill-stop descriptor 와 e8 route descriptor 데이터에는 닿지만 `0x004844d0`/`0x004844d8` fill site 또는 `0x004844dc` fill stop site 로 가는 edge/node 는 0개다. `0x004844dc -> 0x00440c5c` fill-stop descriptor closure 는 2 node/3 edge 의 self-loop 형태이고 current root `0x00540714`, wrapper `0x00542a04`, frontier `0x00542ae8`, reader `0x00542b0c` 로 가는 edge 는 0개다. 별도 descriptor-edge rejection 도 descriptor/route edge `10/0`, root/fill route edge `0/0`, all-target-section `.data` 로 `descriptor-only-no-route-execution-edge` 를 고정한다. 따라서 obvious descriptor-pointer bridge 는 닫혔고, 실제 실행 trace 또는 non-linear VM path decode 전까지 `descriptorBridgeProofFound=False`, promotion 은 blocked 다.
- 같은 descriptor bridge gap 도 top-level proof/missing-gate 형식으로 맞췄다. `out/save_selector_predecessor_descriptor_bridge_gap.*` 는 `proofFound=False`, `failedDescriptorBridgeGateIds=root-stop-to-fill-bridge,fill-stop-to-current-bridge,route-execution-target-edge,descriptor-encoded-route-target-control-flow,runtime-or-decoded-nonlinear-vm-path`, `missingEvidence=5`, `evidenceRefs=3` 을 직접 싣고, fill-site execution context, route queue, promotion gate, completion audit 이 이 값을 전파한다. 따라서 descriptor closure 가 c0/e8 descriptor data 에만 닿고 fill/current route execution edge 로 승격되지 못하는 이유를 source report 한 줄에서 확인할 수 있다.
- 이번 p1 pass 는 같은 field-entry runtime sweep 를 `out/save_selector_predecessor_fill_execution_order_gap.html` 자체에도 직접 싣는다. `runtime-field-entry-input` evidence 는 22 sequence/85 snapshot, field-entry candidate 0, snapshot route candidate 0, final selector `1:0/50:0/8:0/19:1`, status `field-entry-not-found` 로 고정되며, 이 요약은 `fieldEntryProofFound=False`, `predecessorFieldEntryProofFound=False`, `fieldEntryFailedGateIds=field-entry-input-sequence,selector-2-0-snapshot,route-relevant-runtime-object-tile,selected-root-execution-proof`, `fieldEntryEvidenceRefCount=4` 와 함께 `out/route_investigation_queue.*`, `out/route_promotion_gate.*`, `out/route_blocker_evidence_matrix.*`, `out/completion_audit.*` 에 전파된다. 같은 report 는 이제 coordinate-source context 도 중앙 p1 report 안에 넣어 `coordinateSource=start-coordinate-found-in-image-memory/save-camera-memory-only-no-route-object-coordinate-source`, public-start pointer/static/trail/image `0/1/0/2`, observed-trail `0/0/7/10`, reciprocal `0/0/0/118`, promotion `diagnostic-only` 로 묶는다. 따라서 p1 fill-order blocker 는 local trace/root entry/descriptor/raw generic/field-entry input/coordinate-source 어느 쪽에서도 `1:0 -> 2:0` 실행 순서를 증명하지 못해 blocked 로 유지된다.
- 같은 중앙 p1 fill-order report 는 이제 `evidenceRefs=11` 도 직접 갖는다. refs 는 branch-state execution gap, tail reset, persistence, route order, data descriptor opcode map, dispatch table context, field-entry scan, coordinate-source scan, merge execution/runtime/closure context 로 이어지며, 이 ref count 와 path 목록은 route investigation queue, route promotion gate, blocker matrix, completion audit verifier 가 함께 강제한다.
- P1 next-action refs 는 이제 `out/runtime_predecessor_coordinate_source_scan.json` 도 직접 포함한다. 이 ref 는 public predecessor save load 뒤 start/trail/reciprocal coordinate source scan 의 pair hit summary 를 queue/gate/audit 에 보존한다. 핵심 값은 rejection `save-camera-memory-only-no-route-object-coordinate-source`, public start pointer/static/trail/image `0/1/0/2`, observed trail `0/0/7/10`, reciprocal aggregate `0/0/0/118` 이며 gameplay actor/trail coordinate source 가 없어 promotion 은 blocked 다. 이제 이 report 자체도 `proofFound=False`, `predecessorCoordinateSourceProofFound=False`, `failedPredecessorCoordinateSourceGateIds=public-predecessor-gameplay-object-source,reciprocal-target-actor-or-trail-source,selector-2-0-current-root-execution`, `missingEvidence=3`, `evidenceRefs=4` 를 싣고 P1 next-action refs/verifier 가 강제한다.
- 같은 p1 산출물은 이제 selector merge runtime/closure 결과도 직접 노출한다. `selector-merge-closure` evidence 는 `mergeShapeOnly=True`, `forwardBridgeAbsent=True`, `reverseReuseBeforeFillOnly=True`, `selectorMergeRuntimeProofFound=False`, `selectorMergeClosureProofFound=False`, `predecessorPersistenceUsableForCurrent=False`, `routeOrderAndSelectorMergeClosed=False` 로 고정된다. 이 값도 route investigation queue, promotion gate, blocker matrix, completion audit 에 전파되어 p1 fill-order blocker 와 p2 selector-merge blocker 가 같은 route-order/merge closure 결핍으로 막혀 있음을 한 곳에서 확인할 수 있다.
- `out/save_selector_predecessor_fill_site_execution_context.json` 은 fill-site 실행 문맥을 한 장으로 다시 묶는다. branch-state watch poll 7종은 총 28 sequence/45400 sample 이고 모두 public predecessor `1:0` 은 관측하지만 `2:0`/current root hit 는 0, expected fill match 는 0, all-zero branch-state poll 은 7/7이다. root-entry traversal 은 23 node 뒤 `0x004783e0` 에서 멈추고 root-tail branch target 분류도 `262/80/111/138` 및 fill/current reader branch `0/0` 으로 실행 진입 후보를 만들지 못한다. multi-hop root-tail branch closure 역시 12352 node/7249 edge, branch seed 591개에서 fill/current-reader reach `0/0` 으로 끝나 `branch-closure-no-fill-or-current-reader` 를 보존하며, 밖으로 빠지는 successor 512개는 `262/1/111/138` class 및 `142/3/367` section 분포로 별도 기록한다. encoded-entry scan 은 `raw-encoded-scalars-nonpromoting` raw 4/root-tail 4/promoting 0으로 남으며, 별도 raw-scalar rejection 은 no-fixed/no-branch/branch-attached/scalar-only `4/4/0/4` 로 전부 실행 후보가 아닌 스칼라 일치라고 분류한다. descriptor closure 는 root/fill node `949/2`, fill/current-reader edge `0/0` 이고 descriptor-edge rejection 은 `descriptor-only-no-route-execution-edge`, descriptor/route edge `10/0`, root/fill route edge `0/0` 으로 실행 edge 부재를 별도 gate detail 에 싣는다. trail-start movement 는 1개/11503 sample 에서 보이지만 fill match 는 0이고, target tile 관측은 0개/0 sample, camera-only/actor-or-trail target 은 0/0, target fill/current/route hit 도 0/0/0 이라 `branchStatePollTargetObservationStatus=target-not-observed` 로 non-promoting 고정한다. field-entry sweep 의 22 sequence/85 snapshot 도 snapshot selector `8:0` 10개, `1:0` 64개, `50:0` 4개, `19:1` 7개, snapshot route candidate 0개로 묶어 transient selected-root hit 부재를 함께 고정한다. local fill fragment, root-entry reachability, encoded-entry scan, descriptor bridge, dispatch-slice runtime proof, field-entry sequence scan 을 함께 대조해도 필수 proof gate 6개가 `0/6` pass 이므로 `rootEntryFixedTraversalFillSitesReachable=False`, `descriptorBridgeProofFound=False`, `runtimeFillObserved=False`, `fieldEntryCandidateCount=0`, `fillSiteExecutionContextProven=False`/promotion blocked 로 남긴다.
- `out/save_selector_branch_gate_consistency.html` 은 가장 가까운 `selectionBuffer[0x20]` writer `0x005428bc` 와 frontier reader `0x00542b0c` 의 관계를 고정한다. 두 row 는 같은 `secondaryBranchState`/`selectionBuffer[0x20]` 를 쓰고, 그 사이에 같은 offset 을 다시 쓰는 row 0개 및 valid secondary opcode `0x10` fill 0개가 확인된다. 따라서 known opcode 기준으로는 선택 slot 이 보존되지만, 선택된 state 값이 `1` 인지와 control path/strict hotspot 은 여전히 미증명이라 promotion 은 blocked 다.
- `out/save_selector_gate_offset_sources.html` 은 `0x005428bc` 이후 control gate `0x005428c4`/`0x005428cc` 의 `selectionBuffer[0xe8]`/`[0xea]` source 를 분리한다. current `2:0` root 안에서 두 offset 은 reader 로만 나타나고, 전체 save-selector script scan 에서도 opcode `0x12`/`0x13` writer 가 0개라 inherited/runtime selection-buffer byte 로 분류된다. 따라서 이 gate fallthrough 는 아직 runtime proof 대상이며 promotion 은 blocked 다. 이제 report 는 `proofFound=False`, `failedGateOffsetSourceGateIds=4`, `missingEvidence=4`, `evidenceRefs=3` 도 직접 싣는다.
- `out/save_selector_gate_offset_patterns.html` 은 `0xe8`/`0xea` gate offset 의 전체 selector-root 분포를 고정한다. 두 offset 은 전역 reader 981건, writer 0건의 reader-only inherited gate 이며 각각 27개/33개 selector root 에 퍼져 있다. current root `0x00540714` 의 row 는 `0xe8` 1건, `0xea` 5건뿐이라 이 조건은 `map1_01a` 전용 local setup 이 아니라 runtime/inherited selection-buffer state 로 유지한다. 이 global pattern report 도 `proofFound=False`, `failedGateOffsetPatternGateIds=3`, `missingEvidence=3`, `evidenceRefs=2` 를 갖는다.
- `out/save_selector_selection_buffer_bases.html` 은 `context+0xa8` selection-buffer base pointer 를 고정/계산 경로별로 정리한다. 즉시값 base 는 `0x0059e310`/`0x004576d8` 이고, 계산 base 는 `0x00457750 + index*0xd8`, `0x0059db30` object pointer table, `0x0059dd70` saved pointer table 로 분기한다. static base 기준 `0xe8`/`0xea` 주소의 직접 dword ref 는 0개라, 다음 단계는 current path 의 pointer mode/base 를 runtime 또는 더 구체적인 VM 흐름으로 증명하는 것이다. 이 base report 도 `proofFound=False`, `failedSelectionBufferBaseGateIds=3`, `missingEvidence=3`, `evidenceRefs=1` 를 싣는다.
- `out/save_selector_gate_base_candidates.html` 은 gate offset `0xe8`/`0xea` 를 가능한 `context+0xa8` base 별 save-data offset 으로 되돌려 본다. loader-aware 매핑 기준 `0x004576d8+0xe8/0xea` 는 첫 save block 뒤 6-byte runtime gap 때문에 save offset `0x00e2`/`0x00e4` 로 떨어진다. party slot base `0x00457750 + slot*0xd8` 에서는 이 offset 들이 `Rinshan MP recover/maximum`, `Smashu MP recover/maximum` 같은 stat byte 로 해석되어 opcode `0x11` 이 기대하는 0..11 branch-state index 근거가 약하다. 따라서 남은 후보는 global/save-runtime buffer 또는 object pointer table mode 의 runtime proof 쪽이다. 이 candidate report 도 `proofFound=False`, `failedGateBaseCandidateGateIds=4`, `missingEvidence=4`, `evidenceRefs=3` 를 포함한다.
- `out/save_selector_gate_sample_values.html` 은 공개 sample save byte 를 gate-base 후보에 대입한다. save/runtime block 후보 `0x00e2`/`0x00e4` 는 샘플 6개 모두 `0x00` 이라 0..11 범위지만 샘플 selector 가 `0:0`/`1:0`/`22:0` 뿐이라 current frontier `2:0` 을 덮지 않는다. party-slot stat 후보 `0x015a`/`0x015c`/`0x0232`/`0x0234` 는 모든 공개 샘플에서 0..11 범위 밖이어서 party-slot-base 승격 근거가 더 약해지고, global/save-runtime buffer 또는 object pointer table runtime proof 가 남는다. 이 report 는 `proofFound=False`, `failedGateSampleValueGateIds=4`, `missingEvidence=4`, `evidenceRefs=2` 를 싣는다.
- `out/savedata_sample_coverage.html` 은 공개 `savedat*.dat` 샘플의 selector coverage 를 route blocker 관점으로 묶는다. 샘플 6개는 `0:0`/`1:0`/`22:0` 을 덮고, flack3r 직접 첨부 `savedat2.dat` 는 selector `1:0` 으로 `map2_02d` target-side 묶음을, flack3r ZIP 의 `savedat4.dat` 는 selector `22:0` 으로 `map7_09k` 묶음을 덮는다. 그러나 current frontier `2:0` 과 `map1_01a`/`map2_02d` route-pair 를 함께 덮는 sample 은 여전히 0개라 route promotion sample count 는 0이다. 같은 리포트는 이제 semantic save coverage 도 직접 싣고, editor-backed scene/money/item/stat/skill byte 160/1274개만 mapped 이며 equipment/status/story offset 은 `unmapped-known-editor-coverage-only` 로 남는다는 점을 `out/savedata_sample_deltas.*` 와 같은 숫자로 고정한다. 웹 런타임의 `load savedat` HUD 는 실제 save 를 올렸을 때 selector, `0x00e2/0x00e4` gate byte, active order, active flag 를 표시해 이후 `2:0` 샘플을 받으면 바로 비교할 수 있게 했다.
- `out/synthetic_savedata_selector_probe.html` 과 `out/synthetic_savedat_selector_2_0.dat` 은 selector `2:0` 진단용 합성 savedat 벡터다. save offset `0x0002=2`, `0x0003=0`, tile `34,19` 를 넣어 원본 loader table 해석이 selected pointer `0x00540714` 와 `map1_01a`/`map2_02d` field-map 묶음으로 이어지는지 파서/웹에서 재현한다. WebKit smoke 는 이 파일을 웹의 savedat File/loadSavedatFile 경로로 로드해 route evidence, `saveMapSelect`, `routeAssist`, `map2_02d` frontier 노출을 확인하고, 같은 파일을 zip archive 안에 넣은 synthetic upload 와 `savedatUrl=../SAVEDATA/savedat_zip_probe.zip` 경로도 검사해 `window.HWANSE_LAST_SAVEDAT_ARCHIVE` 와 동일 route evidence 및 save HUD 의 zip member 행이 잡히는지 확인한다. 이 파일은 캡처된 실제 save 나 runtime trace 가 아니므로 route promotion proof 가 아니며, 상태는 `blocked` 로 유지한다. 이제 probe 자체도 `proofFound=False`, `syntheticSavedataProbeProofFound=False`, `failedSyntheticSavedataGateIds=captured-gameplay-save,runtime-selected-pointer-trace,strict-hotspot-or-runtime-trigger`, `missingEvidence=3`, `evidenceRefs=4` 를 top-level 로 싣고, P4 next action refs 가 이 diagnostic/non-proof 상태를 직접 강제한다.
- 2026-06-09 P4 savedata diagnostic refs 는 표준 상태 필드도 맞췄다. `out/synthetic_savedata_selector_probe.*` 와 `out/save_selector_selected_pointer_usage.*` 는 기존 `routePromotionStatus=blocked` 에 더해 top-level `promotionStatus=blocked` 를 싣고, route queue/gate 의 P4 evidenceRefs 도 이 필드를 직접 요구한다.
- `out/save_selector_real_savedata_evidence_gap.html` 은 로컬 `SAVEDATA`/`data` 와 루트의 실제 `savedat*.dat` 후보를 따로 스캔한다. `tools/summarize_save_selector_real_savedata_evidence_gap.py --search-root <file-or-dir-or-zip>` 로 외부 save 도 같은 기준으로 검사할 수 있고, directory scan 은 `.zip` 내부의 `savedat*.dat` 도 추출 없이 후보로 파싱한다. `data/public_savedata/` 에 보존한 공개 sample 6개는 실제 후보/valid 후보로 clean parse 되며 selector `0:0`/`1:0`/`22:0` 을 덮고, flack3r `savedat2.dat` 는 target-side selector `1:0` 의 `map2_02d` 묶음을 덮는다. flack3r ZIP 의 `savedat4.dat` 는 selector `22:0` 의 `map7_09k` 묶음이라 blocker 증거는 아니다. 보고서는 selector distribution 과 captured split 을 따로 보여주며 source-only `0:0` save 2개, target-only `1:0` save 1개, route-pair/current `2:0` save 0개로 고정한다. 이제 SHA-256 dedup 도 같이 기록해 valid real 6개가 unique hash 5개, duplicate group 1개임을 분리하고, required byte coverage 는 slot byte `0x0003=0x00` 이 6/6개에 있지만 group byte `0x0002=0x02` 와 selector byte pair `0x02/0x00` 은 0개임을 직접 보여준다. required captured save checklist 는 `0x0002=0x02`, `0x0003=0x00`, selected pointer `0x00540714`, route maps `map1_01a`/`map2_02d`, intake path `SAVEDATA/savedat1.dat`..`SAVEDATA/savedat9.dat` 와 `SaveData/savedat1.dat`..`SaveData/savedat9.dat` 조건을 명시한다. 현재 `out/savedata_slot_scan.*` 의 로컬 `SAVEDATA/SaveData` slot scan 은 `no-saves-found`, found/valid `0/0`, selector `2:0` 후보 0, real route 후보 0이라 새 캡처 슬롯이 아직 없다. 보고서의 workspace survey 는 생성/추출 산출물 디렉터리를 제외한 전역 scan 에서 expected-size dat 파일 6개와 zip dat member 0개만 발견해 숨은 local selector `2:0` save 후보가 없음을 고정한다. current selector `2:0` save 와 route-promotion save 는 여전히 0개다. route-evidence rejection 은 `real-saves-present-current-selector-absent-synthetic-excluded` 로 고정되어, real saves 는 존재하지만 current selector/current root route proof 가 없고 `out/synthetic_savedat_selector_2_0.dat` 은 합성 진단 파일이라 명시적으로 제외됨을 별도 gate 로 남긴다. current `2:0` route-pair sample 이 없어 실제 캡처 save 또는 runtime trace 전까지 `map1_01a -> map2_02d` 는 `blocked` 다.
- 같은 real savedata 보고서는 valid real 후보 6개를 `validRealCandidateRows` 로 압축해 selector byte pair, selected pointer, source/target/route-pair coverage, route proof 여부와 `blockReasons` 를 행 단위로 노출한다. 현재 6개 모두 `validRealCandidatesAllBlocked=True` 이며 block reason counts 는 selector byte pair mismatch 6, selected pointer mismatch 6, source map 미포함 4, target map 미포함 5, route-pair 미포함 6으로 고정되어 공개 save 후보가 왜 real selector `2:0` proof 로 승격될 수 없는지 queue/gate/audit 에서도 같은 근거로 추적된다.
- 같은 real savedata 보고서는 이제 `evidenceRefs=4` 를 직접 싣는다. refs 는 `out/savedata_slot_scan.json`, `out/savedata_sample_coverage.json`, `out/synthetic_savedata_selector_probe.json`, `out/save_scene_selectors.json` 으로 이어진다. 또한 `out/savedata_slot_scan.*` 자체도 `promotionStatus=blocked`, `proofFound=False`, `savedataSlotScanProofFound=False`, `failedSavedataSlotScanGateIds=local-slot-file-present,valid-slot-savedata,current-selector-2-0,real-route-evidence-candidate`, `missingEvidence=4`, `evidenceRefs=4` 를 top-level 로 싣고, MD/HTML 은 `Missing Evidence`/`Evidence Refs` 섹션을 보여준다. 현재 로컬 slot scan 의 `no-saves-found` 및 public sample/synthetic selector/selector table 근거가 route investigation queue, route promotion gate, blocker matrix, completion audit verifier 에 같은 ref count 로 전파되며, verifier 가 queue/gate 의 P4 next action 에서 이 slot-scan proof fields 를 요구한다.
- `out/legacy_hwanedit_editor_gap.html` 은 flack3r 공개 ZIP 안의 legacy `3586_hwanedit-sya2727-rudals1323.exe` 를 로컬 `/tmp` 추출본 기준으로 bounded metadata/string/control-name evidence 만 기록한다. SHA-256 은 `edd79d260d58efed59842bcb4c6cf9c1788dd360a4734c85a52fc0c7c93fdb83`, save filter 는 present, stat control 은 46개(`TxtAtahoMaxHP`, `TxtMoney`, `TxtSmashuNowMP` 등)지만 route keyword count 는 0이고 selector/route-promotion evidence 는 false 다. 따라서 이 legacy editor 는 savedat stat/item 편집 표면 근거일 뿐 selector `2:0`, selected pointer `0x00540714`, strict hotspot, normal-route execution proof 를 제공하지 않아 `map1_01a -> map2_02d` 승격 증거가 아니다.
- 2026-05-31 SKYDC editor source recheck 는 no=19336/no=7891/no=11683 다운로드가 모두 같은 194,264-byte UPX-packed GeoCube/NewsGo wrapper(`cdbdfbbee7947e87bc6de1ae718ed947f606c8bf205df16b20341c7b6573b33e`) 를 반환함을 확인했다. `WININET.dll`, `ShellExecuteA`, `InternetOpenA`, `GeoCube`, `newsgo.kr` string/import 만 보이고 `savedat*.dat`, selector `2:0`, selected pointer `0x00540714`, route-pair payload 는 없어서 captured savedata 로 보존하지 않으며 route promotion evidence 도 아니다.
- 2026-06-01 public web recheck 는 `savedat2.dat`/`savedat`, `환세취호전`, `Hwanse`, SKYDC targeted search 에서 기존 flack3r sample 과 SKYDC editor/full-game archive 계열만 다시 확인했고, non-synthetic selector `2:0` captured savedat 후보를 새로 찾지 못했다.
- 추가 follow-up search 는 `환세취호전 세이브파일`, `환세취호전 savedat1.dat`, `환세취호전 세이브 savedat`, `savedat*.dat 환세취호전`, `환세취호전 savedat2.dat savedat 세이브 파일`, GitHub-scoped `환세취호전 savedat`/`Hwanse savedat` 및 관련 query 로 HDNua HandyHwanseEditor 글, KLDP/yellowworld editor posts, flack3r 기존 hacked `savedat2.dat`, Ruliweb remaster board snippets, rollingdice guide/archive pages, SKYDC editor download pages, SteamDB `Gensei Suikoden Plus` `SaveData/*.dat` metadata, generic `.dat`/unrelated save-editor 결과를 다시 확인했지만, standalone original captured `savedat*.dat` 후보를 추가하지 못했다. 2026-06-08 추가 재확인도 `환세취호전 savedat2.dat 세이브 파일`, `환세취호전 세이브파일 savedat.dat`, `"savedat2.dat" "환세취호전" -flack3r`, `Hwanse2 savedat.dat 환세취호전`, GitHub-scoped `환세취호전 savedat`/`Hwanse savedat`, `"Hwanse2" "savedat"`, `"환세취호전" "savedat1.dat"` 결과가 같은 공개 sample/editor/unrelated 결과로 수렴했고, 로컬 `SAVEDATA`/`SaveData` slot 디렉터리도 README 만 있어 새 captured selector `2:0` save 후보가 없다. 이 노트는 `out/save_selector_real_savedata_evidence_gap.*`, route queue/gate/blocker/audit 의 `publicSearchNoteCount=26` 로 전파되어 `realSelector20Savedata` gate 를 계속 blocked 로 둔다.
- `out/route_promotion_external_proof_handoff.html` 은 현재 route blocker 의 외부 proof intake 를 한 장으로 묶는다. Captured selector `2:0` savedata 의 기대 size/bytes/path/scan command 와 `tools/refresh_savedata_route_proof.py` one-command refresh, runtime trace point `0x0059e348`/`0x0040c675`/`0x00542b0c`/`0x005428c4`, strict hotspot review, selected-root execution proof, current leaf/wrapper proof, predecessor fill/order proof, selector merge proof, opcode20 gate-base proof, opcode24 producer proof, not-accepted diagnostic evidence, 재생성/검증 명령을 모두 기록하며 verifier 는 이 handoff 가 `achieved=False`/promotion `blocked` 상태와 일치하는지 확인한다. 2026-06-09 부터 handoff JSON/MD/HTML 도 top-level `nextRequiredInputs` 3개(captured selector `2:0` savedata, normal-route selected-root trace/equivalent proof, strict source coordinate/tile-hotspot proof)를 직접 싣는다. `out/current_leaf_wrapper_external_proof_packet.*` 는 current selector `2:0`/root `0x00540714`, wrapper `0x005429ac -> 0x00542a04 -> 0x00542ae8`, reader `0x00542b0c`, route-pair entries `6/8`, negative wrapper `-12` 를 묶되 selected-root execution/index-source/wrapper execution/current selector leaf/strict hotspot proof 가 모두 없어 `currentLeafWrapperExternalProofFound=False` 로 고정한다. 또한 `Required External Inputs` 표로 `real-selector-2-0-save`, `normal-route-runtime-trace`, `strict-source-hotspot` 세 intake id 와 각 accepted signal 을 고정해, captured `2:0` save/normal-route selected-root trace/strict source hotspot proof 중 어느 증거가 들어오면 어떤 refresh command 를 돌릴지 분산 없이 추적한다. 2026-06-09 부터 이 regenerate chain 은 `tools/summarize_current_leaf_wrapper_external_proof_packet.py`, `tools/summarize_selector_merge_external_proof_packet.py`, `tools/summarize_opcode20_gate_base_external_proof_packet.py`, `tools/summarize_goal_completion_checklist.py` 도 포함해, 외부 save/trace/hotspot 증거가 들어온 뒤 `out/current_leaf_wrapper_external_proof_packet.*`, `out/selector_merge_external_proof_packet.*`, `out/opcode20_gate_base_external_proof_packet.*`, `out/completion_audit.*`, external handoff, `out/goal_completion_checklist.*`, verifier 가 같은 상태로 갱신되게 한다.
- 2026-06-09 external proof template 추가: `out/route_promotion_external_proof_template.*` 는 `real-selector-2-0-save`, `normal-route-runtime-trace`, `strict-source-hotspot` 세 next input 을 `schemaVersion=1` 템플릿으로 고정한다. 각 record 는 accepted signal, required checks, submit/refresh path, example record 를 싣고, runtime trace 는 4개 accepted trace point, strict hotspot 은 top/bottom/left/right candidate side 를 보존한다. `templateStatus=no-external-proof-submitted` 이며 template 자체는 proof 로 승격하지 않는다. `tools/summarize_route_promotion_external_proof_handoff.py` 와 `tools/verify_web_assets.py` 가 handoff 링크와 template files 를 강제한다.
- 2026-06-09 external proof validation 추가: `tools/validate_route_promotion_external_proof.py` 는 제출된 external proof JSON(record/list/wrapper)을 `real-selector-2-0-save`, `normal-route-runtime-trace`, `strict-source-hotspot` 세 input id 별 required checks 로 검증해 `out/route_promotion_external_proof_validation.*` 를 쓴다. 기본값은 `out/route_promotion_external_proof_template.json` 이므로 현재 산출물은 `inputMode=template-only`, `recordCount=0`, `proofFound=False`, `promotionStatus=blocked`, `notPromotionByItself=True` 다. 제출 record 를 강제로 판정할 때는 `python3 tools/validate_route_promotion_external_proof.py <submitted-proof.json> --require-accepted` 를 쓰며 accepted record 가 없으면 exit 1 로 실패한다. Full refresh 와 함께 판정할 때는 `python3 tools/refresh_savedata_route_proof.py --proof-json <submitted-proof.json> --require-accepted-proof` 를 사용하며, 이 옵션은 refresh chain 안의 validator 에 같은 제출 JSON/require flag 를 넘긴다. Savedata record 는 실제 파일이 있으면 기존 `scan_savedata_slots` 파서로 size 1274, selector `2:0`, selected pointer `0x00540714`, route pair `map1_01a/map2_02d`, synthetic diagnostic false 를 다시 확인하고, runtime trace/hotspot record 는 accepted trace point 및 strict tile proof 조건을 별도 체크한다. `tools/verify_route_promotion_external_proof_validator.py` 는 template-only `--require-accepted` 실패, runtime trace fixture 수락, wrapper/list 안의 mixed accepted/rejected record 처리, strict hotspot fixture 수락, selector-only strict hotspot 거부, `out/synthetic_savedat_selector_2_0.dat` 거부를 CLI exit code 까지 smoke-test 한다. `tools/refresh_savedata_route_proof.py` 와 external handoff regenerate chain 은 이 validator 도 실행하지만, validation 은 proof intake sanity check 일 뿐 route promotion 을 자동 승격하지 않는다.
- 2026-06-09 browser savedat intake 도 같은 외부 proof checklist 를 노출한다. `savedatRouteEvidence()` 는 selector, selected pointer, source/target route pair, synthetic diagnostic 여부를 `missingEvidence[]`/`missingEvidenceCount`/`externalProofInputId=real-selector-2-0-save` 로 계산하고, `HWANSE_LAST_SAVEDAT_ROUTE_EVIDENCE`, `HWANSE_LAST_SAVEDAT_DROP`, zip archive rows/selected row, `HWANSE_LAST_SAVEDAT_SCAN`, title public savedat marker 에 같은 fields 를 복사한다. public `flack3r-savedat2` 샘플은 real save 이지만 selector `1:0` 이라 proof 가 아니며 `selector 2:0`, `selected pointer 0x00540714`, `map1_01a->map2_02d route pair` 3개 missing evidence 를 HUD 의 `route missing ... +1` 줄과 browser smoke/audit 에 남긴다.
- `out/completion_audit.html` 의 current blocker 행도 이제 `route_promotion_external_proof_handoff.html` 과 package ids(`captured-selector-2-0-savedata`, `runtime-trace-or-equivalent-selected-root-proof`, `strict-source-hotspot-review`, `selected-root-execution-proof`, `current-leaf-wrapper-proof`, `predecessor-fill-order-proof`, `selector-merge-proof`, `opcode20-gate-base-proof`, `opcode24-runtime-producer-proof`) 를 직접 싣는다. 따라서 `/goal` 재개 시 completion audit 에서 바로 외부 proof intake 로 이어지며, verifier 는 이 handoff 링크와 command/package set 을 route gate/audit 양쪽에서 강제한다.
- 2026-06-09 completion audit blocker 도 route queue/gate 와 같은 hard-gate missing evidence 표면으로 맞췄다. `out/completion_audit.*` 의 `confirmedRouteBlockers[0].missingEvidence` 는 이제 strict source coordinate, tile hotspot confirmation, selected-root execution ref, real selector `2:0` captured savedata, runtime trace/equivalent selected-root proof 5개를 직접 싣고, 기존 frontier-only 3개는 `frontierMissingEvidence` 로 보존한다. `hardMissingEvidenceExtra` 는 real savedata/runtime trace 2개를 계속 표시해 과거 frontier blocker 에 추가된 hard gate 를 추적한다.
- `out/route_blocker_evidence_matrix.html` 도 같은 external proof handoff 링크와 package ids 를 related report/top-level evidence 로 보존한다. 이제 route promotion gate, blocker matrix, completion audit, external handoff 네 산출물이 모두 동일한 외부 증거 intake 를 가리키고, current leaf/wrapper proof package 까지 같은 목록에 있으므로 captured `2:0` savedata 나 runtime/strict-hotspot proof 를 받았을 때 갱신 위치가 분산되지 않는다.
- 2026-06-09 `out/route_promotion_external_proof_handoff.html` 의 captured savedata intake 도 browser scan `../web/game.html?savedatScan=1` 을 클릭 가능한 링크로 제공한다. 따라서 `SAVEDATA/` 또는 `SaveData/` 에 새 captured save/zip 을 넣은 뒤 handoff 페이지에서 바로 브라우저 slot scan 으로 넘어가 selector `2:0`/selected pointer `0x00540714`/route-pair 판정을 확인할 수 있다. `tools/summarize_route_promotion_external_proof_handoff.py` 와 `tools/verify_web_assets.py` 가 이 링크 계약을 고정한다. 이는 외부 savedata proof intake 속도를 높이는 표면 보강이며, 실제 captured selector `2:0` save 가 없으므로 route promotion 은 계속 blocked 다.
- 2026-06-01 runtime trace execution probe 를 재실행해 `out/runtime_trace_execution_probe.*` 와 `out/runtime_trace_feasibility.*` 를 갱신했다. Probe 내부에서는 qemu-i386 binfmt 가 enabled 로 보이고 relocated trace points 도 `0x002be348`/`0x0012c675`/`0x00262b0c`/`0x002628c4` 로 계산되지만, WineDbg attach/launch, Hwanse2.exe startup, virtual desktop attach, QEMU gdbstub watchpoint/breakpoint 경로가 여전히 안정적인 watchpoint session 을 만들지 못해 `canCaptureTraceNow=False`/`canRunRuntimeTraceNow=False` 로 남는다. 이번 pass 에서 QEMU gdbstub 도 virtual desktop launch(`wine explorer /desktop=hwanse,640x480 Hwanse2.exe`) 를 별도로 시험하도록 보강했고, connect control 은 성공하지만 relocated software breakpoint 는 PE runtime address 를 읽지 못한 채 remote connection 이 닫히고 relocated watchpoint 는 hardware watchpoint insertion 실패로 끝난다. `out/route_promotion_gate.*` 와 `out/completion_audit.*` 도 execution probe count `18`, virtual desktop gdbstub `0/False/False`, relocated soft/watch `0/False/True/0/False/True` 를 직접 보존한다. 따라서 `runtimeTraceOrEquivalent` hard gate 는 계속 blocked 다.
- 2026-06-09 runtime trace execution probe 도 top-level proof/gate 형식으로 표준화했다. `out/runtime_trace_execution_probe.*` 는 `promotionStatus=blocked`, `proofFound=False`, `runtimeTraceExecutionProofFound=False`, `failedRuntimeTraceExecutionGateIds=3`, `missingEvidence=3`, `evidenceRefs=3` 를 직접 싣고, P8 route queue/gate refs 와 verifier 가 이 status/proof blocker 를 강제한다.
- `out/strict_source_hotspot_external_review_packet.html` 은 strict source/tile hotspot proof 를 외부에서 검토하거나 보강할 때 필요한 후보 4개를 한 파일로 모은다. 각 후보의 source tile, target spawn, routeAssist/target review URL, coordinate hit 상태, variant scan, tile signature match/rejection 을 행 단위로 싣고, right 후보의 `centerPairStrictEventMatch=11` 이 모두 rejected `map1_02b->map1_01a` review 에만 속하며 target-spawn low3x3 match `140` 도 unrelated/generic owner 로 남는다는 점을 명시한다. `out/route_promotion_external_proof_handoff.html` 의 strict-source package 는 이 packet URL 과 candidate sides 를 직접 링크하고 verifier 는 둘을 함께 강제한다.
- 같은 strict-source external review packet 도 top-level proof/missing-gate 형식으로 맞췄다. `out/strict_source_hotspot_external_review_packet.*` 는 `proofFound=False`, `strictSourceHotspotExternalReviewProofFound=False`, `failedStrictSourceHotspotReviewGateIds=strict-source-coordinate,tile-hotspot-confirmation,strict-target-link,equivalent-runtime-trigger-proof`, `missingEvidence=4`, `evidenceRefs=19` 를 직접 싣는다. External handoff 도 같은 failed ids/missing/ref count 를 전파하므로 strict source hotspot/tile hotspot 외부 review 에서 strict coordinate/event row, route review/tile hotspot, strict target link, equivalent runtime trigger 중 어떤 proof 가 빠졌는지 바로 확인할 수 있다.
- `out/selected_root_execution_external_proof_packet.html` 은 selected-root execution proof 를 외부/후속 증거 기준으로 분해한다. Save-loader selector `2:0` real sample 0, static current-root text ref 0, selected-pointer hook prerequisites unproven, opcode `0x07/0x08/0x09` non-current producer 0, current-root writers internal-only, real/public runtime poll route hit 0, constructed `2:0` diagnostic excluded 등 8개 subgate 가 모두 non-promoting 임을 한 표로 보존한다. Route-pair entry `6/8` 은 corrected trace 로 reader 에 닿지만 normal non-negative selection proof 가 없고 reader-bearing negative entry `-12`/wrapper `0x00542a04 -> 0x00542ae8` 도 current root 에서 선택되지 않아, `entry 6/8` 또는 wrapper `-12` 실행 proof 가 다음 accepted signal 로 남는다. `out/route_promotion_external_proof_handoff.html` 의 selected-root package 는 이 packet URL, subgate count `8/8`, entry indices `6,8`, negative reader `-12` 를 직접 링크하고 verifier 가 강제한다.
- 같은 selected-root external packet 도 top-level proof/missing-gate 형식으로 맞췄다. `out/selected_root_execution_external_proof_packet.*` 는 `proofFound=False`, `selectedRootExternalProofFound=False`, `failedSelectedRootExternalGateIds=save-loader-selected-root,save-selector-dispatch-table-anchor,static-current-root-references,selected-pointer-hook-prerequisites,global-opcode-07-08-09-selected-pointer-paths,current-root-writer-paths,runtime-selected-pointer-probes,constructed-selector-2:0-diagnostic-exclusion`, `missingEvidence=5`, `evidenceRefs=8` 을 직접 싣는다. External handoff 도 같은 failed ids/missing/ref count 를 전파하므로 selected-root 증거 intake 에서 real selector save, selected pointer runtime proof, non-current producer/control-flow, dispatch slice execution, strict hotspot 중 어떤 proof 가 빠졌는지 바로 확인할 수 있다.
- `out/predecessor_fill_external_proof_packet.html` 은 priority 1 predecessor fill/order blocker 를 외부 proof packet 으로 분리한다. Predecessor `1:0` 에서 current `2:0` 으로 이어지는 fill site 는 `0x004844d0,0x004844d8` 이고 opcode `0x10` 의미 자체는 decoded 되었지만, local trace 는 `0x004844d0 -> 0x004844dc` 에서 `no-fixed-advance` 로 멈추며 current reader `0x00542b0c` 에 닿지 않는다. Proof gate 는 `0/10` pass, blocked IDs 는 `localFillStreamReachesCurrentReader`, `rootEntryFixedTraversalReachesFillSites`, `descriptorSliceRuntimeDispatchProven`, `runtimeObservedPredecessorFill`, `routeOrderAndSelectorMergeClosed` 등 10개 전부다. Public predecessor branch-state poll 도 all-zero/fill match 0 이므로 packet 의 accepted signal 은 normal runtime fill observation, save-selector slice dispatch proof, selector merge/order proof 로만 남긴다. `out/route_promotion_external_proof_handoff.html` 은 이제 이 packet URL 과 blocked gate IDs 를 직접 링크하고 verifier 가 강제한다.
- 같은 predecessor fill external packet 도 top-level proof/missing-gate 형식으로 맞췄다. `out/predecessor_fill_external_proof_packet.*` 는 `proofFound=False`, `predecessorFillExternalProofFound=False`, `failedPredecessorFillExternalGateIds=localFillStreamReachesCurrentReader,rootEntryFixedTraversalReachesFillSites,fillFragmentEntryCandidateFound,encodedFillEntryControlFlowCandidateFound,rootTailBranchClosureReachesFillOrReader,descriptorSliceRuntimeDispatchProven,rawGenericRouteProofFound,runtimeObservedPredecessorFill,predecessorToCurrentForwardBridgeFound,routeOrderAndSelectorMergeClosed`, `missingEvidence=10`, `evidenceRefs=6` 을 직접 싣는다. External handoff 도 같은 failed ids/missing/ref count 를 전파하므로 P1 외부 증거 intake 에서 어떤 proof 를 가져와야 하는지 packet 과 handoff 양쪽에서 바로 확인할 수 있다.
- 2026-06-09 `out/selector_merge_external_proof_packet.html` 은 priority 2 selector merge blocker 를 외부 proof packet 으로 분리한다. Current selector `2:0` 은 source `0:0` + predecessor `1:0` set shape 처럼 보이고 `currentEqualsPredecessorPlusSource=True`, `sourcePredecessorUnionCoversCurrent=True` 이지만, union extra map `map1_02b`, source/current bridge `0/0`, predecessor/current forward bridge `0`, direct/encoded merge bridge `False/False`, reverse current-to-predecessor `51/51/0` 이 모두 before-fill only 로 남아 `mergeShapeOnly=True` 다. Packet gate 는 `0/7` pass, blocked IDs 는 shape-only, source/current bridge, predecessor/current bridge, execution-like bridge/root ref, selected-root runtime execution, predecessor fill route-order proof, strict source hotspot 전부이며, accepted signal 은 source/current VM edge, predecessor/current forward bridge, execution-like merge bridge, real selected-root runtime execution, predecessor fill/route-order proof, strict hotspot 뿐이다.
- 같은 selector merge external packet 도 top-level proof/missing-gate 형식으로 맞췄다. `out/selector_merge_external_proof_packet.*` 는 `proofFound=False`, `selectorMergeExternalProofFound=False`, `failedSelectorMergeExternalGateIds=selector-merge-execution-proof,selected-root-runtime-execution,predecessor-fill-route-order-proof,strict-source-hotspot`, `missingEvidence=4`, `evidenceRefs=10` 을 직접 싣는다. External handoff, route promotion gate, route blocker matrix, web playtest route, completion audit 은 package id `selector-merge-proof` 와 이 packet URL 을 전파하므로 P2 selector merge blocker 를 shape evidence 와 execution/order proof gap 으로 분리해 한 곳에서 확인할 수 있다.
- 2026-06-09 `out/opcode20_gate_base_external_proof_packet.html` 은 priority 7 opcode `0x20` gate-time base blocker 를 외부 proof packet 으로 분리한다. Current writer `0x005428bc` 뒤 gate `0x005428c4/0x005428cc` 앞의 유일한 local base-affecting 후보는 `0x005428a8` opcode `0x20` mode 0 nested descriptor runner 이지만, direct `context+0xa8` setter 는 0개이고 nested-table setter 5개도 runtime object/descriptor state 없이는 route base 가 아니다. Descriptor+4 field/frontier/gate refs 는 `0/0/0/0`, all-script selection-shaped rows 는 362개지만 specific gate base false, encoded route-target class 는 `no-encoded-route-target-scalars-in-descriptor-scripts` 다. Diagnostic active-order sample 210개와 public predecessor active-order sample 1689개는 descriptor `0x004f867c` 를 안정적으로 보지만 각각 constructed diagnostic 또는 selector `1:0` predecessor-only 상태라 current `2:0`/route proof 로 승격하지 않는다.
- 같은 opcode20 gate-base external packet 도 top-level proof/missing-gate 형식으로 맞췄다. `out/opcode20_gate_base_external_proof_packet.*` 는 `proofFound=False`, `opcode20GateBaseExternalProofFound=False`, `failedOpcode20GateBaseExternalGateIds=opcode20-runtime-base-path,predecessor-state-persistence,strict-source-hotspot`, `missingEvidence=3`, `evidenceRefs=19` 를 직접 싣는다. External handoff, route promotion gate, route blocker matrix, web playtest route, completion audit 은 package id `opcode20-gate-base-proof` 와 이 packet URL 을 전파하므로 active order 관측과 gate-time `context+0xa8` base proof 를 분리해 추적할 수 있다.
- `out/opcode24_runtime_producer_external_proof_packet.html` 은 priority 8 opcode `0x24` mode1 runtime producer blocker 를 외부 proof packet 으로 분리한다. Mode1 source `0x0059e348` 은 PE zero-filled `.data` tail 의 static `0x00` 이고 savedata-backed 가 아니며, direct/source-write scan 은 rows/covering/indexed/static `95/0/0/0`, indirect base/window/nearby `0/0/0`, ReadFile/global/mode1 `30/2/0`, broad block-write candidates `259/0` 이다. Runtime enabled flag `0x0059e34d` 는 refs/direct writes `12/0` 이고 static dispatch proof 가 없으며, runtime polls 는 `runtime-flag-nonroute-mode1-zero`, flag-one sample `340`, mode1 nonzero `False`, source-save diversion `48:13` 으로 남는다. Accepted signal 은 `0x0059e348` write watchpoint, `0x0040c675` mode1 read breakpoint, same-path selected-root/strict-hotspot proof 뿐이다. Handoff 는 이 packet URL, mode1 source/read/boundary, runtime classification 을 직접 링크하고 verifier 가 강제한다.
- 여섯 external proof/review packet 도 원본 입력 refs 를 직접 싣는다. Strict-source review packet 은 refs 19개(strict hotspot review matrix, strict event tile signature, hotspot gap, coordinate/byte/CNS/resource/payload/pattern/target-link/frontier/edge-trigger reports, manifest/root point scan, entry/frontier context, scene-record cluster context, selector bridge refs), selected-root packet 은 refs 8개(real savedata gap, selected-pointer usage, dispatch table context, global selected-pointer paths, current writer paths, runtime selected-pointer poll, patched diagnostic exclusion, predecessor route attempt), predecessor fill packet 은 refs 6개(fill execution/order, fill-site context, opcode10 context, branch-state execution gap, descriptor bridge gap, merge runtime context), selector merge packet 은 refs 10개(predecessor persistence/route order, merge runtime/closure/execution, set decomposition, target alias, route-root ref, reverse reuse, merge bridge matrix), opcode20 gate-base packet 은 refs 19개(current writer paths, opcode20 nested/descriptor/sample/pass/base/context scans, active-order runtime polls, gate offset/base/sample reports), opcode24 runtime-producer packet 은 refs 12개(mode1 runtime/source/indirect/file/block, runtime-enabled flag/block, default effect, current-root modes, runtime flag poll, trace feasibility/execution probe)를 갖고 verifier 가 ref path 와 `evidenceRefCount` 를 강제한다.
- 같은 handoff 는 이제 모든 package 에 direct report path 를 둔다. Captured savedata package 는 `save_selector_real_savedata_evidence_gap.html`, `savedata_slot_scan.html`, browser `../web/game.html?savedatScan=1` 를 링크하고, runtime-trace package 는 `runtime_trace_feasibility.html` 과 `runtime_trace_execution_probe.json` 를 링크한다. 따라서 handoff HTML 하나에서 real save intake, trace feasibility, strict hotspot, selected-root, predecessor fill/order, selector merge, opcode20 gate-base, opcode24 producer 증거를 모두 따라갈 수 있으며 verifier 가 이 direct URL 들을 강제한다.
- `out/save_selector_selection_buffer20_provenance.html` 은 `selectionBuffer[0x20]` 의 route-root provenance 를 분리한다. 전역 writer/reader 는 813/127개이고 writer/reader root 는 35/32개이며, current `2:0` root `0x00540714` 는 writer 18/reader 6개와 `map1_01a`/`map2_02d` 를 모두 포함한다. 하지만 source-side `0:0` root `0x00501808` 은 writer 4/reader 2개로 source-only 이고 predecessor `1:0` root `0x00478364` 은 writer 0/reader 3개로 target-only 라서, root-level count 만으로는 normal transition 을 promote 하지 않는다. 가장 가까운 current writer 는 `0x005428bc`, frontier reader 는 `0x00542b0c` 이며, runtime branch-state 값/control path/strict hotspot 증거가 남아 상태는 `blocked` 다.
- `out/save_selector_gate_pass_matrix.html` 은 corrected save/runtime gate byte 와 predecessor `1:0` state 가설을 함께 평가한다. save/runtime base 라면 공개 샘플의 `0xe8`/`0xea` index 는 모두 `0` 이고, predecessor case0 table 에서는 `secondaryBranchState[0]=1` 이라 `0x005428c4`/`0x005428cc` 두 gate 가 모두 fallthrough 한다. zero-table 대조군은 0/4 sample 만 통과하고 party-slot stat 값은 16/16 모두 0..11 밖이므로, 남은 증명은 gate 시점 `context+0xa8` base, `1:0 -> 2:0` 상태 보존, strict `map1_01a` hotspot 이다. 이 pass matrix 도 `proofFound=False`, `failedGatePassMatrixGateIds=4`, `missingEvidence=4`, `evidenceRefs=3` 를 직접 보존한다.
- `out/save_selector_gate_base_proof_gap.html` 은 gate-time `context+0xa8` base 증명 공백을 현재 stream 기준으로 고정한다. `0x005428bc` activation window 에서 gate 전 direct base setter 는 0개이며, 유일한 base-affecting 후보는 `0x005428a8` opcode `0x20` mode 0 nested descriptor runner 다. opcode `0x20` handler signature 는 7/7개가 맞고, 이 handler 는 slot descriptor pointer 를 `0x00457750 + slot*0xd8` 에서 읽은 뒤 mode 0 에서 `descriptor+4` nested stream 을 `0x00402360` 으로 실행한다. nested runner 는 context stream 을 임시 교체해 general handler table `0x00440538` dispatcher 로 들어가지만, `descriptor+4` field-map/current-frontier ref 와 gate reader/writer 는 여전히 0/0 및 0/0이고, `descriptor+4` direct/encoded route-target scalar 도 0/0/0이다. 전체 `descriptor+0/+4/+8` script 의 selection-buffer opcode 모양 row 362개도 gate `0xe8`/`0xea` reader/writer 0/0, all-slot direct/encoded route-target scalar 0/0/0, all-slot specific gate base false 로 끝난다. patched diagnostic `2:0` active order 는 count/order `0x01/[0x00]` 로 descriptor 0 `0x004f867c`/`cara_at1.cns` 를 고르지만, 그 `descriptor+4` 는 field-map/current-frontier/gate row 와 encoded route-target scalar 가 0/0/0/0이고 `context+0xa8` non-pointer setter 도 0개이며 마지막 setter 는 `pointer-dword-low-byte-collision` 이라 diagnostic-only/non-promoting 이다. 같은 constructed left-route hit 는 첫 stability poll 에서 route hit 125개를 보지만 selector-only recheck 와 active-order recheck 는 모두 route hit 0이고 active-order count 도 `0x00x679` 로 남아 gate base 를 증명하지 못한다. public predecessor direction sweep active-order poll 은 8개 sequence/3378 sample 중 selector `1:0` public row 1689개에서 active order `0x01/[0x00]`, runtime descriptor `0x0021867c` -> static `0x004f867c`, `runtimeSlotBaseTable0=0x00177750`, object table `0x0027be00,0x0027d2f8,0x0027d5d4` 를 안정적으로 관측했지만 `2:0`/current root/route context 는 0건이라 real-state calibration evidence 이면서도 non-promoting 이다. 따라서 opcode `0x20` runtime descriptor/order 또는 equivalent runtime trace 없이 route promotion 은 blocked 다.
- `out/save_selector_opcode20_nested_base_modes.html` 은 current activation row `0x005428a8` 의 opcode `0x20` nested script 경로를 분리한다. 현재 값 `0x00200020` 은 mode 0 이므로 `0x00457750 + slot*0xd8` save/object slot 의 `descriptor+4` script 를 `0x00402360` 으로 실행하고, nested dispatcher 는 general handler table `0x00440538` 을 사용한다. handler signature scan 은 stream+1 mode read, slot count `0x004576e8`, descriptor table `0x00457750 + slot*0xd8`, mode 0 `descriptor+4`, mode 1 `descriptor+0`, nested runner call, save-selector stream `+4` advance 를 7/7개 모두 확인했다. nested runner 는 context stream 을 교체/복구해 save-selector stream 을 inline 실행하지 않고 general dispatcher 로 넘긴다. 이 테이블에는 `context+0xa8` 를 `0x0059e310`, `0x004576d8`, save slot base, object pointer table, saved pointer table 로 바꾸는 handler 가 섞여 있어, 실제 runtime descriptor script/base 없이는 `0xe8`/`0xea` gate 를 통과 증거로 삼을 수 없다. 이 report 는 `proofFound=False`, `failedOpcode20NestedBaseGateIds=4`, `missingEvidence=4`, `evidenceRefs=4` 를 싣는다.
- `out/save_selector_opcode20_slot_sources.html` 은 opcode `0x20` mode 0 의 slot count/source 를 save-loader block 과 연결한다. `0x004576e8` count byte 는 첫 save block 의 save offset `0x0010` 이고, `0x00457750` slot base 는 두 번째 save block 의 offset `0x0072` 로 0xd8-byte slot 3개를 담는다. 정적 EXE slot first dword 는 모두 0이라 nested `descriptor+4` script 는 runtime slot descriptor pointer materialization 이 확인되기 전까지 추적할 수 없고, `map1_01a -> map2_02d` promotion 은 blocked 유지다. top-level audit fields 는 `proofFound=False`, `failedOpcode20SlotSourceGateIds=4`, `missingEvidence=4`, `evidenceRefs=3` 이다.
- `out/save_selector_opcode20_slot_descriptor_writers.html` 은 slot first dword writer 를 descriptor table 관점으로 고정한다. `0x004321cd`/`0x004323dd`/`0x0043271f` 는 active order byte `0x004576e9+index` 를 `0x00442d95` table 에 넣어 descriptor pointer 를 고르고, 이를 `0x00457750 + slot*0xd8` 첫 dword 에 쓴다. 따라서 current `opcode 0x20` mode 0 이 따라갈 `descriptor+4` script 는 runtime active order/count 없이는 특정할 수 없으며 promotion 은 blocked 다. top-level audit fields 는 `proofFound=False`, `failedOpcode20DescriptorWriterGateIds=4`, `missingEvidence=4`, `evidenceRefs=2` 이다.
- `out/save_selector_opcode20_descriptor_scripts.html` 은 descriptor table `0x00442d95` 의 12개 row 에서 `script+0/+4/+8` 를 스캔한다. `script+0` 은 `cara_at1.cns`, `cara_rs1.cns`, `cara_sm1.cns`, `btl_*.cns`, `zsa_*.cns` 등 character/battle/object resource script 로 분류되고, `descriptor+4` 의 field-map CNS record 와 current frontier direct ref 는 각각 0개다. 추가로 current root/frontier/source/target 주소에 대한 descriptor+4 encoded route-target scalar 와 전체 script-slot encoded route-target scalar 도 각각 0/0/0으로 `no-encoded-route-target-scalars-in-descriptor-scripts` 다. `descriptor+4` 의 base 선택 opcode 모양 row 는 43개지만 27개는 포인터 dword 의 low byte 충돌이고, non-pointer `context+0xa8` setter 모양 row 16개는 모두 object pointer table `0x42` 쪽이다. 전체 `script+0/+4/+8` selection-buffer opcode 모양 row 는 `127/126/109` 총 362개지만 gate offset `0xe8`/`0xea` reader/writer 는 전체 script slot 에서도 0/0이라 all-slot specific gate base 역시 false 다. 따라서 `opcode 0x20` descriptor script 경로는 `map1_01a -> map2_02d` promotion 근거가 아니다. top-level audit fields 는 `proofFound=False`, `failedOpcode20DescriptorScriptGateIds=4`, `missingEvidence=4`, `evidenceRefs=3` 이다.
- `out/save_selector_opcode20_object_base_candidates.html` 은 위 16개 non-pointer `0x42` object-base selector 를 행 단위로 분리한다. 전부 `stream+1 == 0` 이라 handler `0x00406480` 의 `dword[0x0059db30 + context[0xf2]*4]` 선택 경로이고, fixed `stream+2` object index 후보는 0개다. 각 후보 뒤쪽 script window 에서 gate `0xe8`/`0xea` selection row, field-map CNS record, current-frontier direct ref 가 모두 0개라 이 행들은 generic runtime object-base reselection 일 뿐 specific gate-base proof 가 아니다. 이 report 도 `proofFound=False`, `failedOpcode20ObjectBaseGateIds=4`, `missingEvidence=4`, `evidenceRefs=3` 를 보존한다.
- `out/save_selector_opcode20_sample_order_effects.html` 은 공개 sample save 의 active count/order byte 를 descriptor 효과에 대입한다. `0:0` 과 target-side `1:0` sample 은 count 1/order `[0]`, progressed `22:0` sample 은 count 3/order `[0,1,2]` 이다. 세 unique sample state 의 마지막 shaped `context+0xa8` row 는 saved pointer table처럼 보이지만 포인터 low-byte collision 이고, non-pointer context setter 는 없다. current frontier selector `2:0` 을 덮는 sample 도 없어 calibration evidence 이며 promotion 은 blocked 다. top-level audit fields 는 `proofFound=False`, `failedOpcode20SampleOrderGateIds=4`, `missingEvidence=4`, `evidenceRefs=2` 이다.
- `out/save_selector_opcode20_order_space.html` 은 opcode `0x20` active order 후보를 3-slot capacity 기준으로 전수 열거한다. descriptor 12개에서 unique-index order 는 1464개, repeat-allowed 상한은 1884개이며 field-map record/current-frontier ref/gate writer/gate reader 를 포함하는 direct proof order 는 양쪽 모두 0개다. unique order 중 1424개가 non-pointer `context+0xa8` object-table base 를 만들 수 있지만 이는 generic runtime object pointer 경로이고, active order alone 은 route 를 promote 하지 않는다. 이 order-space report 는 `proofFound=False`, `failedOpcode20OrderSpaceGateIds=4`, `missingEvidence=4`, `evidenceRefs=3` 를 포함한다.
- `out/save_selector_opcode20_context_f2_sources.html` 은 opcode `0x20` object-base 후보가 의존하는 `context+0xf2` byte 를 코드 참조 관점으로 전수 집계한다. `.text` 에서 `context+0xf2` 참조는 204개(읽기 141/쓰기 63)이고, object table `0x0059db30` reader 는 65개, 직접 initializer 는 2개, 부모 context copy writer 는 61개, constant write 는 0개다. 즉 `context+0xf2` 는 고정 selector 값이 아니라 runtime object-slot selector 이며, current `2:0` sample/active order/object table state 가 없으면 `map1_01a -> map2_02d` gate object 를 특정할 수 없어 promotion 은 blocked 다. top-level audit fields 는 `proofFound=False`, `failedOpcode20ContextF2GateIds=4`, `missingEvidence=4`, `evidenceRefs=4` 이다.
- `out/save_selector_opcode20_runtime_materializers.html` 은 active order/count materializer 를 save-selector stream 과 분리한다. save-load path 는 save block read 이후 selector pointer 선택 전 `0x0042349c -> 0x00432323` 으로 slot descriptor 를 재구성한다. 이후 add/remove 는 general nested handler table `0x00440538` 의 opcode `0x62`/`0x63` 이며, current selector `2:0` leaf 에 보이는 low byte `0x63` row 들은 save-selector table `0x00440720` 에서 `face_01.cns` resource word 로 해석된다. descriptor script scan 에도 general `0x62`/`0x63` row 는 0개라 opcode `0x20` self-mutation path 는 제거됐지만, current `2:0` active order 자체는 아직 public sample 로 증명되지 않아 blocked 다. top-level audit fields 는 `proofFound=False`, `failedOpcode20RuntimeMaterializerGateIds=4`, `missingEvidence=4`, `evidenceRefs=5` 이다.
- P7 증거 전파 패스에서는 위 opcode `0x20` gate-time base path 의 행 단위 증거를 queue/gate/audit 산출물에 보존하도록 고정했다. `out/route_investigation_queue.json` 의 priority 7 action 은 gate window row 7개, local base-affecting row 1개, remaining proof 3개, gate offset source/pattern rows, gate base candidate/sample/pass-matrix rows, selection-buffer base rows, opcode20 object-base/order-space/context+0xf2/slot-source/descriptor-script/slot-writer/sample-order/runtime-materializer rows 를 직접 참조한다. 2026-06-09 추가 pass 에서는 context+0xf2 ref/read/write `204/141/63`, runtime object-table reader `65`, initializer/copy/constant write `2/61/0`, object selector/fixed-stream2 selector `16/0`, diagnostic object-table evidence, `fixedContextF2ValueProvenForCurrentFrontier=False`, `activeOrderAlonePromotesRoute=False`, `runtimeObjectTableStateRequired=True` 도 P7 refs 에 직접 넣었다. `out/route_promotion_gate.json` 및 `out/completion_audit.json` verifier 도 같은 P7 refs 를 강제하므로, active-order-only proof 가 제거된 상태에서도 opcode `0x20` runtime descriptor/order 또는 equivalent runtime trace 가 없으면 promotion 이 열리지 않는다는 결론이 count-only 요약이 아니라 row-backed 증거로 유지된다.
- `out/save_selector_opcode24_payload_table.json` 은 `0x005428e4` opcode `0x24` 뒤쪽 payload/action table 을 포인터 closure 와 payload pointer graph 로 분리한다. `0x005428e8..0x005429a4` 구간의 dword pointer 는 7개 edge/4개 component 로 모두 payload 내부에 닫히고 external edge 는 0건이며, `0x005429a8` leaf table, `0x00542a04` wrapper, `0x00542ae8` frontier leaf, `0x00542b0c` reader 를 직접 가리키지 않는다. 따라서 가장 가까운 writer `0x005428bc` 뒤의 `0x24` payload 는 frontier leaf 선택 증거가 아니라 blocked 증거로 유지한다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/opcode24_action_payload_patterns.json` 은 savedata slot 자체를 해석하지 않고 EXE selector VM root 전체에서 opcode `0x24` mode 1 action/state payload 패턴을 전역 비교한다. 전체 mode 1 후보는 1332개/65 selector root 이고, 현재 boundary 값 `0x0c000124` 는 100개/51 root 에 반복된다. 모든 mode 1 후보의 다음 16 dword 안에는 frontier leaf/reader, false target, `map1_01a.cns`/`map2_02d.cns` 직접 operand 가 0건이라 현재 `0x005428e4` 는 strict transition opcode 가 아니라 generic action/state payload 로 분류하고 promotion 은 blocked 로 유지한다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_dispatch_stop_context.json` 은 `0x005428f4` low byte `0xe8` dispatch stop 을 별도 검증한다. save-selector handler table `0x00440720` 의 `0xe8` entry `0x00440ac0` 은 `0x00440c28` `.data` descriptor 를 가리키며, 이 값의 포인터 참조 6개도 모두 `.data` 에 있다. 즉 executable code handler 가 아니므로 `0x00542ae8` frontier leaf 선택이나 `0x00542b0c` reader 도달 증거가 아니며, route promotion 은 blocked 로 유지한다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_dispatch_table_context.json` 은 save-selector decoder table `0x00440720` 이 generic handler table `0x00440538` 의 `0x7a` entry 뒤 slice 로 static anchoring 되는지 확인한다. generic indexed dispatch immediate 는 `0x0040234c -> 0x00440538` 1건이고, `0x00440720` direct dword ref/indexed dispatch 는 0건이다. relative opcode `0x07`/`0x08`/`0x09` 와 branch `0x10..0x13` handler 는 기대값으로 매핑되지만, 이는 static decoder anchoring 일 뿐 selected root `2:0` 실행 증거가 아니므로 selected-root execution gap 은 blocked 로 유지한다. route-relevant low byte 비교도 함께 고정해 `0xe8` 이 slice 에서는 `0x00440c28` `.data` descriptor 로 떨어지지만 raw generic dispatch 에서는 default handler `0x0040239f` 로 처리됨을 기록한다. 또한 `.text` 의 register-base `call/jmp [base + index*4 + disp]` 동적 dispatch scan 은 3개 site(`0x00438456`, `0x004390b7`, `0x004390f3`)만 남기고, 셋 모두 `state==-1` sentinel 과 `index*3` triplet walk 를 쓰는 SEH scope-table callback 으로 분류되며 주변 immediate 에 `0x00440720` 이 없어 dynamic save-selector table-base static candidate 는 0개다. 이제 `dynamicScopeTableCallbackRows` 는 이 세 site 를 행 단위로 보존하고 `dynamicSaveSelectorTableBaseCandidateRows` 는 빈 리스트로 고정해, dynamic dispatch 후보가 save-selector table-base switch 증거가 아님을 count 뿐 아니라 row evidence 로도 보여준다. 이번 pass 는 direct absolute indexed dispatch 와 동적 dispatch 116행을 함께 대상으로 `0x00440538 + 0x1e8` 또는 direct `0x00440720` table-base 산술 후보를 검사했고 후보 0건이다. 특히 generic dispatcher `0x0040234c` 는 `generic-table-immediate-only` 로 분류되어 `0x00440538` immediate 1건만 갖고 `0x1e8`/`0x00440720` 근접 immediate 는 없다. route-relevant slice row 6개는 generic u8 dispatch 로는 slice handler 에 byte-reachable 하지 않고, data descriptor row 도 save-selector table-base switch proof 없이는 0개만 generic byte-reachable 하므로 `tableBaseSwitch=6/0` 으로 유지된다. 따라서 descriptor boundary 해석은 아직 `0x00440720` slice runtime dispatch proof 또는 dynamic/table-base arithmetic switch proof 에 의존하며, 이 역시 promotion 증거가 아니다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- 같은 dispatch-table context 도 top-level proof/missing-gate 형식으로 맞췄다. `out/save_selector_dispatch_table_context.*` 는 이제 `proofFound=False`, `dispatchTableProofFound=False`, `failedDispatchTableGateIds=save-selector-slice-runtime-dispatch,descriptor-boundary-runtime-bridge,dynamic-save-selector-table-base-candidate,route-relevant-slice-table-base-switch`, `missingEvidence=4`, `evidenceRefs=3` 을 직접 싣고, predecessor fill execution/order, fill-site context, branch-state gap, route queue, promotion gate, completion audit 이 이 값을 전파한다. 따라서 `0x00440720` slice static anchoring 과 dynamic SEH callback row 는 보존하되, runtime dispatch proof/table-base switch/descriptor-boundary bridge 가 아직 없다는 blocker 원인을 한 줄에서 추적할 수 있다.
- `out/save_selector_data_descriptor_opcode_map.json` 은 route-relevant low byte 들이 가리키는 `.data` descriptor 를 opcode/table 관점으로 분리한다. route dispatch stop `0x005428f4` 와 wrapper child pointer `0x00542a08` 은 모두 low byte `0xe8` 로 `0x00440c28` descriptor 에 떨어지고, 이 descriptor 는 byte-opcode entry `0xa7`/`0xaf`/`0xe0`/`0xe8` 및 table-aligned ref `0x100`/`0x109` 와 공유된다. 반면 direct current-root leaf entry `0x005429f4` 는 `0xc0 -> 0x00440c5c` 별도 descriptor 를 쓴다. predecessor 쪽 stop 도 같은 방식으로 닫혀 `0x004783e0` 은 low byte `0xd0 -> 0x00440a9c`, `0x004844dc` 는 low byte `0xc0 -> 0x00440c5c` descriptor boundary 로 해석된다. 따라서 이 stop 들은 wrapper/frontier leaf 실행 또는 predecessor fill-site 도달 증거가 아니라 data-descriptor boundary 증거이며, `0x00542a04`/`0x00542ae8` runtime selection, predecessor root 에서 fill fragment 로 넘어가는 non-linear path, strict hotspot 이 여전히 필요하다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_opcode24_globals.json` 은 opcode `0x24` mode 1/2 source byte 와 주변 `0x0059e330..0x0059e34f` 런타임 글로벌 직접 참조를 함께 보여준다. 주변 object/status byte 들은 참조가 많지만 `0x0059e348` 은 여전히 `0x0040c675` 단일 read 만 있고 direct writer 가 0개라 selector leaf chooser 로 승격하지 않는다. 인접 mode 2 byte `0x0059e347` 의 writer 는 `0x0040fb1c -> 0x0040fb21` 에서 current runtime object index `0x0059e33e` 를 복사하는 경로라, mode 1 `0x0059e348` producer 로 취급하지 않는다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_opcode24_runtime_enabled_context.json` 은 같은 handler 의 runtime enabled flag `0x0059e34d` 를 별도 gate 로 고정한다. `0x0040c51e` 가 이 byte 를 읽고, 값이 1이면 `0x0040c538` mode dispatch 로 들어가지만 1이 아니면 `0x0040c52c` 에서 stream 을 `+4` advance 하고 mode-specific object update 를 건너뛴다. 이 flag 역시 `.data` zero-filled tail 에 있고 static initial `0x00`, save-loader block 포함 false, direct `.text` writer 0/read 12 이므로, 현재 opcode `0x24` mode 1 실행도 runtime flag producer 없이는 정적 승격 근거가 아니다.
- `out/save_selector_opcode24_mode1_source_writes.json` 은 opcode `0x24` mode 1 source byte `0x0059e348` 의 producer 를 static write 관점으로 다시 좁힌다. `0x0059e348` 을 덮는 absolute store, `0x0059e340..0x0059e350` indexed-displacement write 후보, address-immediate producer 후보가 모두 0건이라 현재 source 는 unresolved runtime byte 로 유지한다. 이 report 는 `proofFound=False`, `failedOpcode24Mode1SourceWriteGateIds=3`, `missingEvidence=3`, `evidenceRefs=3` 을 직접 싣는다.
- `out/save_selector_opcode24_mode1_block_writes.json` 은 same source 를 broad block write 관점으로 다시 훑는다. `0x0059e300..0x0059e348` dword ref 259건 중 `0x0059e310` address-like covering base 2건은 size/call 조합이 없어 block write 후보가 아니며, direct covering write 와 block write candidate 는 각각 0건이다. 따라서 obvious static `memset`/`memcpy` 형 producer 도 제거하고 runtime trace 필요성을 유지한다. 이 report 는 `proofFound=False`, `failedOpcode24Mode1BlockWriteGateIds=3`, `missingEvidence=3`, `evidenceRefs=3` 을 직접 싣는다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_opcode24_runtime_enabled_block_writes.json` 은 runtime flag `0x0059e34d` 를 broad block-write 관점으로도 닫는다. `0x0059e300..0x0059e34d` dword ref 333건 중 address-like covering base 는 2건이지만 covering size immediate 가 없어 block-write candidate 는 0건이고 direct covering write 도 0건이라, mode dispatch flag 도 static memset/memcpy-style producer 없이 runtime trace 필요 상태로 남는다. 이 report 는 `proofFound=False`, `failedOpcode24RuntimeEnabledBlockWriteGateIds=3`, `missingEvidence=3`, `evidenceRefs=3` 을 직접 싣는다.
- `out/save_selector_opcode24_mode1_runtime_context.json` 은 `0x0059e348` 이 `.data` raw end `0x00559e00` 이후 zero-filled tail 에 있어 파일 raw byte 가 없고 process start 값은 0이라는 점을 고정한다. 또한 save loader 의 세 read block(`0x004576d8..0x0045774a`, `0x00457750..0x004579d8`, `0x0059db60..0x0059dd60`) 밖에 있으므로 savedata-backed selector 나 static leaf chooser 로 승격하지 않는다. indirect runtime producer 가 확인되기 전까지 이 경로도 blocked 다.
- `out/save_selector_opcode24_mode1_indirect_context.json` 은 `0x0059e310` global selection buffer 기준의 `+0x38` 간접 후보와 `0x0059e300..0x0059e348` alternate base 후보를 확인한다. `0x0059e310` 직접 ref 는 31건이고 `context+0xa8` 할당은 3건이며, base immediate 뒤 add row 는 `+0x11`/`+0x12` 뿐이다. `+0x38 == 0x0059e348` materialization, exact mode1 write, short-window `[base+0x38]` write 후보가 모두 0건이고, `0x0059e340+0x08` 같은 주변 base short-window write 후보도 0건이라 이 경로도 blocked 상태로 남긴다. 이 report 는 `proofFound=False`, `failedOpcode24Mode1IndirectGateIds=3`, `missingEvidence=3`, `evidenceRefs=4` 를 직접 싣는다.
- `out/save_selector_opcode24_mode1_file_read_context.json` 은 위 `+0x11`/`+0x12` base rows 가 실제 `ReadFile` 1-byte destination 인지 별도 고정한다. `ReadFile` IAT `0x005a041c` call 은 30개이고, `0x0059e300..0x0059e350` global destination 은 `0x004232b1 -> 0x0059e321(+0x11)` 및 `0x004232e8 -> 0x0059e322(+0x12)` 2건뿐이다. 둘 다 size 1이라 `0x0059e348(+0x38)` 을 덮지 않으며 mode1 file-read candidate 는 0건이다. 따라서 같은 global-buffer load 함수 안의 obvious file-read producer shape 도 non-promoting 으로 닫고 runtime watchpoint/동등 증거 필요성을 유지한다. 이 report 는 `proofFound=False`, `failedOpcode24Mode1FileReadGateIds=3`, `missingEvidence=3`, `evidenceRefs=3` 을 직접 싣는다.
- `out/save_selector_opcode24_current_root_modes.json` 은 current selector `2:0` root `0x00540714..0x00543578` 안의 low-byte `0x24` 후보를 전수 스캔한다. 28개 hit 중 executable pointer low-byte collision 9개를 제외하면 opcode 후보 19개, mode1 후보 18개가 있고, 알려진 gate boundary `0x005428e4`/`0x0c000124` 도 이 반복 패턴 안에 있다. 후보들의 다음 4개 dword 안에는 frontier leaf `0x00542ae8`, frontier reader `0x00542b0c`, false target `0x0053f46f`, `map1_01a.cns`, `map2_02d.cns` 직접 operand 가 모두 0건이므로, mode1 opcode 자체를 strict map transition 으로 승격하지 않는다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_opcode24_mode1_default_effect.json` 은 opcode `0x24` mode 1 의 static/default 효과를 object `+0x61` consumer 증거와 묶는다. `0x0059e348` 의 static 값 0 때문에 기본 object `+0x61` 값은 `0x03` 이지만, save-backed source 와 static producer 는 없고 direct/branch frontier operand 는 0건이며 유일한 branch operand 는 `0x00542e74 -> 0x00001618`/`map2_16j.cns` 이다. 따라서 기본 mode1 효과도 `map1_01a -> map2_02d` promotion 근거가 아니며 runtime producer trace 또는 strict hotspot 이 필요하다. 이 report 는 `proofFound=False`, `failedOpcode24Mode1DefaultEffectGateIds=3`, `missingEvidence=3`, `evidenceRefs=4` 를 직접 싣는다.
- `out/route_investigation_queue.html`, `out/route_promotion_gate.html`, `out/completion_audit.html` 은 위 opcode `0x24` mode 1 source-write/runtime-context/default-effect 증거를 같은 blocker row 에 묶는다. action 8 은 `0x0059e348` 의 direct/static writer, savedata backing, `0x0059e310+0x38` base path, broad block-write, static default promotion 이 모두 막힌 상태, `0x0059e347` mode 2 object-index cache, `0x0059e34d` runtime enabled flag 의 static-dispatch proof gap 및 runtime-flag broad block-write candidate 0건을 한 줄로 보여주며, 다음 필요한 증거를 runtime producer trace 또는 strict source hotspot 으로 유지한다. 같은 route queue/gate row 는 `hotspotGap`, `frontierReaderBranchContext`, `frontierPayloadShape`, `eventShapeScan`/scene adjacency non-promoting 증거도 함께 보존한다. 그래서 strict hotspot 부재(`eventTransitions=0`, `coordinateCandidates=0`, `targetSelectorOnlyContexts=5`)와 reader `0x00542b0c` fallthrough payload `0x0053f4fc` 의 in-bounds point 0개, false target `cara_01.cns`, sibling field-map target 0개, resource gate payload 3/3개가 paired character image rect table 로 맞고 text ref 0건인 점이 strict source coordinate/resource-gate 다음 액션에 같이 표시된다.
- P8 증거 전파 패스에서는 opcode `0x24` mode1 producer blocker 도 row-backed 상태로 고정했다. priority 8 action 은 source-write rows 95개, indirect base rows 2개, file-read destination rows 2개, mode1 block rows 259개, runtime context save-read blocks/remaining proofs 3/3개, runtime-enabled refs/save-read blocks/remaining proofs 12/3/3개, runtime-enabled block rows 333개, default object+0x61 consumer groups/remaining proofs 6/3개를 직접 참조한다. `route_promotion_gate` 와 `completion_audit` 도 같은 row count 를 포함해, `0x0059e348` 의 static/direct/savedata/default promotion 이 닫혔지만 runtime producer trace 또는 strict hotspot 없이는 여전히 blocked 라는 결론을 보존한다.
- `out/save_selector_opcode24_mode1_runtime_context.*` 는 이제 자체 `evidenceRefs=10` 을 싣는다. refs 는 save-loader read block, mode1 source-write scan, constructed selector `2:0` diagnostic poll, indirect/file-read/block-write scans, default-effect report, runtime-enabled flag context, opcode24 runtime flag context, runtime trace execution probe 를 직접 가리킨다. `route_investigation_queue`, `route_promotion_gate`, `route_blocker_evidence_matrix`, `completion_audit`, `verify_web_assets` 도 같은 ref count/path 를 검증해 P8 runtime producer blocker 를 원본 증거 파일까지 역추적할 수 있게 했다.
- `out/route_promotion_gate.html` 의 hard gate evidence 는 `out/map1_01a_strict_source_hotspot_context.json` 요약도 직접 포함한다. 현재 strict-source context 는 후보 4개, review/event 0/0, strict source/tile hotspot `False/False`, coordinate/variant scan blocked, target-spawn coordinate scan `targetSpawnCoord=80/18/43/0/True` 및 `targetSpawnClasses={"selector-script-word":18}/{"character-descriptor-script-word":43}` 로 current-root/character hit 전부가 non-promoting script word 임을 고정하고, byte-coordinate scan blocked(`byteCoord=24/0/0/66/False`, `targetByteCoord=24/0/15/False`), CNS payload coordinate scan blocked(`cnsPayload=24/0/0/14/0/False`), tile match center 11 but low3x3/pair3x3 0 이고 이 center 11건도 rejected review only(`centerPairRejectedReview=11`, `allCenterPairMatchesRejectedReview=True`)라 non-promoting 이다. target-spawn tile signature 도 `targetSpawnSig=points:0,matches:0/147/0,targetMap:0/0/0,zero:True/True/True` 로 center/pair3x3/target-map strict event match 가 없고 low3x3 147건은 generic-only 라 승격하지 않는다. resource points 163/route-exit points 0, reader branch `resource-gate-before-scene-record`, target selector-only source overlap/source-target pair cluster `1/1`, current frontier breadth maps/route-pairs/source-outgoing/target-incoming `11/110/10/10`, generic edge-trigger source/auto boundary 후보 `2/2`, helper/controller transition rel hit 0, route immediate hit 0, direction-latch refs/window hits `79/0/0`, global map-loader/script-runner/selector-table rel hits `0/4/0`, script-runner call-window hit `4/0/0/0`, selected-pointer immediate window hit `6/0`, caller-window actor/helper hit `1/0/0;20/0/0`, encoded route-target scalar scan 도 edge handler/local/callgraph `0/0/0/0/0` 및 global contrast `4/4/0/0/0`(`edge-encoded-route-target-scalars-nonpromoting`)로 고정되어 edge status `blocked-generic-edge-trigger-unproven`, selector-only `True`, proof `False` 로 남는다.
- `out/map1_01a_strict_source_hotspot_context.*` 는 이제 자체 `evidenceRefs=19` 를 싣는다. refs 는 strict hotspot review matrix, strict event tile signature, hotspot gap, coordinate/byte/CNS scans, resource ref scan, scene payload/pattern contrast, strict target link gap, frontier reader/payload/scene adjacency, edge-trigger gap, manifest/root point scan, entry/frontier context, scene-record cluster context, selector bridge refs 를 직접 가리킨다. 이 count/path 는 route queue, promotion gate, blocker matrix, completion audit, verifier 에 전파되어 strict-source/tile-hotspot blocker 의 원본 증거를 한 단계로 추적할 수 있다.
- 같은 gate 의 real selector `2:0` save 항목은 workspace-wide savedata survey 와 로컬 slot scan 을 같이 보존한다. 현재 실제 후보는 6개/valid 6개, workspace `.dat` 6개/expected-size 6개, zip/hidden expected-size 후보 0개이며 captured split 은 source-only `0:0` 2개, target-only `1:0` 1개, route-pair/current `2:0` 0개다. 로컬 `SAVEDATA/SaveData` slot scan 은 `no-saves-found` 및 found/valid `0/0` 이고 selector `2:0`/real route 후보도 `0/0` 이다. selector `2:0`, selected pointer `0x00540714`, route pair, route promotion 을 만족하는 real save 는 모두 0개라 synthetic diagnostic 은 계속 제외된다. 이 상태는 `real-saves-present-current-selector-absent-synthetic-excluded` rejection 으로 route gate/audit 에 전파된다.
- 같은 gate 의 selected-root execution 항목은 selected pointer usage 와 route-root ref context 도 직접 싣는다. `0x0059de30` global 은 `.text` ref 6개와 runtime hook 6개가 있어 추적점으로 남지만, hook local window 의 route-specific hit 는 `6/0` 이고 current root `0x00540714`/level2 `0x005429dc` 는 `.text` ref 0개이며 route root refs 는 table-only/text-ref false/route-order false 라 selected-root execution proof 로 승격하지 않는다. handler-rooted hook call graph 도 `selected-pointer-handler-callgraph-generic-only-contrast` 로, root/function/call `4/15/27`, route/current/record/selector/branch `0/0/0/0/0`, generic selected-pointer/selector-table `6/1`, depth sensitivity `4/True/True` 만 남긴다. dispatch gate 도 `dispatchRefs=0/0`, `dispatchDynamic=3/3/0`(indexed/SEH-scope/table-immediate), `tableBaseSwitch=6/0` 으로 route promotion gate 와 completion audit 에 전파되어, 새 동적 dispatch scan 역시 현재는 selected-root execution proof 가 아니라 negative/static-gap evidence 로 남는다.
- 같은 selected-root execution gate 는 priority 1 blocker 인 predecessor fill-site 실행 순서도 직접 노출한다. `0x004844d0/0x004844d8` local fill fragment 는 `0x004844dc` descriptor boundary 에서 멈추고 current reader `0x00542b0c` 에 닿지 않으며, root entry traversal 도 23 node 뒤 `0x004783e0` 에서 멈춰 fill site 에 닿지 않고 direct fill refs 는 0/0이다. root-tail branch audit 은 branch-capable row 591개가 `before-root-tail/inside-root-tail/mapped-.data/unmapped = 262/80/111/138` 으로만 분류되고 fill/current reader branch 는 `0/0` 이라 비선형 branch 후보도 닫는다. 같은 row 는 multi-hop root-tail branch closure `591/7249/0/0` 과 `branch-closure-no-fill-or-current-reader` 를 전파해 branch seed 591개 중 fill/current-reader 로 이어지는 경로가 없음을 promotion gate 에 직접 싣고, closure outside successor 512개도 `262/1/111/138` 및 `.data/.text/unmapped = 142/3/367` 로 분리해 route edge 가 아님을 보존한다. fill-order report 는 encoded raw scalar 후보 4개도 `scalar-only-no-branch-or-fixed-advance` 및 no-fixed/no-branch/branch-attached/scalar-only `4/4/0/4` 로 거절해 control-flow 후보가 아님을 promotion gate 에 직접 싣는다. fill-order report 는 root/fill stop 이 `.data` descriptor boundary 라는 점을 `0x00440a9c`/`0x00440c5c` 로 직접 싣고, route promotion gate 도 `descriptorBoundaries=True` 이지만 `predecessorDataDescriptorBoundaryPromotes=False` 로 유지한다. 추가로 route promotion gate 는 `sliceRuntimeProof=False`, `descriptorDependsOnSlice=True`, `rawGeneralDiffers=2`, `sliceByteReachable=0`, `sliceRequiresTableBase=2`, `sliceDynamic=3/3/0`(indexed/SEH-scope/table-immediate), `sliceDynamicScopeSites=0x00438456,0x004390b7,0x004390f3`, `sliceDynamicTableBaseCandidates=0`, `sliceTableBaseArithmetic=116/0`, `sliceDynamicTableBase=False`, `sliceDynamicTableBaseCandidateSites=-`, `tableBaseReject=table-base-switch-required-no-dynamic-save-selector-candidate` 를 표시해 predecessor boundary 해석도 static slice 모델과 table-base switch proof 에 묶여 있고 동적 dispatch 및 table-base arithmetic scan 모두 save-selector table-base candidate 가 없음을 고정한다. 같은 row 는 raw generic 대안도 `raw-generic-handlers-nonroute-contrast` 및 `raw-generic-callgraph-nonroute-contrast` 로 싣는다. callgraph depth 3 의 function/edge 는 `4/10`, route/fill/current immediate 와 selected/branch immediate 는 `0/0/0` 및 `0/0`, route/fill transfer 는 `0/0`, proof 는 false 이며 depth sensitivity `1..6` 도 proof absent/stable `True/True` 로 유지된다. descriptor bridge 는 `0x004783e0->0x00440a9c` 와 `0x004844dc->0x00440c5c` boundary 를 보지만 root/fill descriptor closure node `949/2`, fill/current-reader edge `0/0`, descriptor-edge rejection `descriptor-only-no-route-execution-edge`, descriptor/route edge `10/0` 으로 root-to-fill/current bridge proof 는 false 이다. fill-site context 는 7종 branch-state poll 28 sequence/45400 sample 에서 public predecessor hit 7, current/route hit 0, fill match 0, all-zero 7 이고, field-entry 22 sequence/85 snapshot 에서도 snapshot route candidate 0개다. 이제 fill-site context 와 branch-state execution gap 도 dispatch-slice runtime proof 를 별도 gate 로 싣기 때문에 필수 proof gate 6개가 `0/6` pass, `fillSiteExecutionContextProven=False` 를 유지한다.
- priority 1 next-action refs 는 이제 `predecessorFillProofGateRows` 10개와 fill-site context `requiredProofGates` 6개를 직접 가리킨다. 따라서 route queue/promotion gate 에서 다음 작업을 열면 local fill stream, root-entry traversal, encoded entry, descriptor slice runtime dispatch, raw generic route proof, runtime fill observation, forward bridge, route-order/selector-merge gate 중 어느 행이 어떤 detail 로 막혔는지 별도 보고서를 다시 찾지 않고 추적할 수 있다.
- 같은 gate 는 selector merge runtime context 도 직접 노출한다. Current `2:0` 은 predecessor `1:0` + source `map1_01a` 모양이고 route pair 를 가진 유일한 selector 이지만, source/predecessor/current forward bridge 는 `0/0/0`, alias public forward 는 0개/address-adjacent forward 는 `10:0` 뿐이며, reverse reuse 는 `51/51/0` 으로 fill site 이전에만 나타난다. selected-root ref 와 any runtime poll route hit 는 false, constructed diagnostic 은 proof 에서 제외, predecessor fill context 와 route-pair entry execution 과 strict hotspot 이 모두 false 라 `selectorMergeRuntimeProofFound=False`/gap open 으로 남는다.
- 같은 gate 는 current selector leaf/wrapper execution gap 도 직접 노출한다. Wrapper `0x005429ac -> 0x00542a04 -> 0x00542ae8` 은 reader `0x00542b0c` 를 품지만 current root pointer 앞의 negative entry `-12` 쪽이고, current root 는 wrapper 를 직접 참조하지 않는다. Wrapper refs 는 `1/1/0/1/0`(전체/current-root-range/current-root-entry-run/opcode5a-fallthrough/promoting)이고, 유일한 current-root-range ref `0x0054090c` 는 opcode `0x5a` mode0 뒤 fallthrough word 이며 그 word 를 stream opcode 로 보면 `0xac -> 0x00000003` non-code handler 라 wrapper jump 로 승격하지 않는다. 전역 leaf-table 은 current route-pair index `-13,-12,6,8`, negative/non-negative route-pair row `2/2`, frontier leaf negative-only 를 고정한다. Route-pair descriptor 2개는 corrected trace 기준 reader 에 닿지만 opcode `0x07` row 33개 중 wrapper/table/current/negative/frontier slot 선택이 모두 0건이고 source/predecessor current producer 도 `0/0/0` 이라 leaf/wrapper/current-selector execution proof 는 false 로 유지된다. current root table window `0x005429a8..0x00542a10` 직접 참조는 `14/0` refs/text refs 이고 전부 `.data` 이며, route entry/leaf/frontier leaf/reader text refs 는 `0/0/0/0`, frontier reader direct refs 는 `0` 이라 corrected reader trace 는 table-shape 증거로만 남는다.
- 같은 gate 는 opcode `0x20` gate-time base proof gap 도 직접 노출한다. Gate 직전 local base setter 는 `0/1`이고 유일한 후보는 `0x005428a8` mode 0 nested descriptor runner이며, opcode `0x20` handler signature 는 7/7개가 맞는다. 이 runner 는 descriptor `+4` stream 을 context stream swap 뒤 general handler table `0x00440538` 로 실행하지만, descriptor `+4` script 는 field/current/gate writer/reader `0/0/0/0` 이고 non-pointer `context+0xa8` setter 모양 16건도 specific gate base 를 증명하지 못한다. Public predecessor active-order poll 은 `1689` sample 에서 `1:0`/order `0x01/[0x00]` 을 보지만 route hit 와 gate-base proof 는 false이고, patched `2:0` diagnostic `210` sample 도 `diagnostic-only` 다. 추가로 diagnostic recheck 는 route hit `125/0/0`, active-order count `0x00x679`, gate-base-open `True` 로 노출되어 promotion 은 blocked 다.
- `out/map1_01a_strict_hotspot_review_matrix.html` 은 `map1_01a -> map2_02d` geometry 후보 4개를 transition review/event/coordinate-ref/coordinate-variant/tile signature 관점으로 교차검증한다. route review row 0개, source review row 0개, strict event transition 0개이며, 확인된 review ledger 는 `map1_02b -> map1_01a` incoming record `0x00503350` 의 confirmed 2/rejected 22뿐이다. 네 후보 모두 coordinate ref 와 variant scan 이 non-promoting 이고 low-nibble tile signature match 4/4는 diagnostic-only 라서 strict source hotspot/tile hotspot confirmation 은 여전히 missing 으로 유지한다.
- `out/map1_01a_strict_source_hotspot_context.json` 은 strict source/hotspot proof gate 를 통합한다. 후보 4개 모두 route review/event row 가 0개이고 coordinate refs/variant scans 는 blocked 다. 이번 pass 에서 top `18,0`, bottom `16,47`, left `3,14`, right `34,19` 후보별 target hint, coordinate xy/yx hit, variant current-root/character hit, source/target standability, block reasons 를 `candidateSummaries` 로 승격했고, routeAssist 재현 URL 과 target spawn review URL 도 같은 행에 직접 싣는다. 네 후보가 모두 같은 5개 사유(`no map1_01a->map2_02d transition-review row`, `no strict map1_01a event transition`, coordinate refs non-promoting, variant strict coordinate absent, tile signature geometry-only)로 blocked 라 `candidateAllBlocked=True` 및 `candidateBlockReasonCounts=4x5` 를 route queue/promotion gate/blocker matrix/completion audit/verifier 까지 전파한다. coordinate variant scan 은 tile/one-based/outside/tile*16/runtime origin/runtime center 에 더해 원본 projection bias `+24/+8` screen-bias 표현까지 80개 coordinate encoding 을 검사하지만 strict coordinate evidence 는 false 다. reciprocal `map2_02d` target-spawn 좌표도 같은 80개 encoding 으로 스캔해 targetSpawn current-root/character hits `18/43` 을 분리했고, 전체 current-root hit 는 `selector-script-word=18`, character descriptor hit 는 `character-descriptor-script-word=43`, promotable hit 는 0으로 닫힌다. 따라서 strict target-spawn coordinate evidence 는 false 이고, route gate 는 target spawn hit 를 strict source trigger 로 승격하지 않는다. byte-coordinate scan 도 source byte-pair 24건/axis+span sequence 16건과 reciprocal target-spawn byte-pair 24건을 검사했지만 strict source-target byte hit 0건, target-spawn strict byte hit 0건, sequence hit 0건, source/target current selector-root byte collision `66/15` 건이라 non-promoting 이다. CNS payload scan 은 압축해제된 `map1_01a.cns` 가 정확히 37x48 u16 2-layer tilemap(7108 bytes)뿐임을 확인하고 byte/word/packed scan `24/24/24`, sequence scan 32건에서 header/layer/outside hit `0/14/0`, strict CNS coordinate evidence `False` 로 고정한다. tile signature 는 right 후보의 center pair 11건만 겹치지만 전부 `map1_02b -> map1_01a` 소유의 rejected incoming review 이고 same-source/target-linked/confirmed center match 는 0개라 low3x3/pair3x3/target-linked/direct source-target match 와 함께 non-promoting 이다. target-spawn signature 는 target map strict event point 0개, center/pair3x3 match 0개, target-map match 0개이며 low3x3 strict-event overlap 147건은 target-linked/direct evidence 없이 generic-only 로 남는다. 이번 pass 에서 이 147건을 owner/review 상태로 쪼개 `map2_03l->map2_01c,map2_13c:45`, `map1_02b->map1_01a:20`, `map9_01e->map2_04l,map2_05e,map2_06e,map2_08e,map6_01e:20` 등이 상위 owner 임을 고정했고, `map2_02d` target-linked 는 0, confirmed/rejected review split 은 `1/19`, `targetSpawnLow3x3GenericOnly=True` 라 tile hotspot confirmation 으로 승격하지 않는다. resource window 는 10개 direct refs 와 163 point-like payload 를 보지만 route-exit point 후보는 0개이고, current frontier 의 18개 point 후보도 `sentinel-0x003f-singleton` 16개와 `resource-size-singleton` 2개뿐이라 hotspot table 로 승격하지 않는다. reader branch 는 resource-gate-before-scene-record 다. target selector-only cluster 5개 중 source 를 함께 담는 cluster 는 current frontier 1개뿐이며, 그 frontier 의 `map1_01a -> map2_02d` 는 11개 map/110개 route-pair broad scene-list 조합 중 1개다. 여기에 generic edge-trigger gap 도 같은 gate 로 묶어 source/auto boundary 후보 `2/2`, transition rel hit 0, route immediate hit 0, direction-latch refs/window hits `79/0/0`, global map-loader/script-runner/selector-table rel hits `0/4/0`, script-runner call-window `4/0/0/0`, selected-pointer immediate window `6/0`, caller-window actor/helper hit `1/0/0;20/0/0`, edge handler/local/callgraph encoded route-target scalar `0/0/0/0/0` 과 contrast `4/4/0/0/0`, direct callgraph indirect jump table `6/58` entry 와 target `58/54` unique 가 모두 actor-controller/collision-helper local(`46/12`, outside 0), status `blocked-generic-edge-trigger-unproven` 으로 고정한다. 이 묶음은 `selector-only-scene-list-no-strict-hotspot` rejection 으로 route gate/audit 에 전파되며 `strictSourceHotspotProofFound=False`/promotion blocked 로 남는다.
- `out/runtime_trace_feasibility.html` 은 다음에 필요한 runtime trace 환경과 정확한 중단점을 고정한다. 로그인/세션 복구 뒤 `tools/probe_runtime_trace_execution.py` 를 다시 실행했지만 `can capture trace now: False` 로 재확인됐고, `out/runtime_trace_execution_probe.*`, `out/runtime_trace_feasibility.*`, `out/route_promotion_gate.*`, `out/completion_audit.*` 도 같은 blocked 상태로 재생성했다. 현재 summary 의 `/proc` view 에서는 `qemu-i386` binfmt 가 disabled/미등록이고 CLI child smoke 도 실패하지만, embedded execution probe 는 한 시점에 qemu-i386 binfmt registered 를 관측했다. 두 관측이 달라도 WineDbg/control watchpoint 는 모두 실패하므로, binfmt 상태와 별개로 debugger/watchpoint trace path 는 unavailable 로 남긴다. 남은 blocker 는 WineDbg notepad attach/launch crash, `Hwanse2.exe` 일반 startup crash, virtual desktop 상태의 WineDbg attach/watchpoint 실패, 안정적인 Wine debugger path 부재, QEMU user-mode gdbstub 의 route watchpoint/breakpoint 삽입 불안정성이다. Wine audio 를 비활성화하고 `tools/runtime_trace_null_alsa.conf` 를 적용해 ALSA 장치 오류는 줄였다. 일반 startup 은 여전히 qemu segfault 로 종료되지만, `wine explorer /desktop=hwanse,640x480 Hwanse2.exe` virtual desktop probe 는 timeout 까지 프로세스를 유지한다. 다만 살아 있는 `Hwanse2.exe` 에 WineDbg attach/watchpoint 를 걸면 error 5 로 실패한다. notepad control probe 도 WineDbg attach 는 같은 error 5, WineDbg launch 는 qemu assertion/segfault 로 실패하므로 현재 중단은 Hwanse 전용 문제가 아니라 qemu-i386/WineDbg 조합의 debugger 경로 문제로 본다. QEMU user-mode gdbstub 은 일반 launch 와 virtual desktop launch 모두에서 연결 control 까지는 성공하지만 `0x0059e348` watchpoint/`0x0040c675` breakpoint 삽입 또는 실행이 안정적이지 않아 WineDbg 우회 경로도 blocked 로 둔다. 추가로 `out/runtime_memory_snapshot.json` 의 loaded base `0x00120000` 를 적용해 trace point 를 `0x002be348`/`0x0012c675`/`0x00262b0c`/`0x002628c4` 로 보정한 relocated gdbstub probe 도 일반/virtual desktop 양쪽으로 실행했지만, gdb 는 Wine loader entry 에서 정지한 상태라 Hwanse PE runtime address 를 아직 읽지 못하고 relocated breakpoint/watchpoint 경로도 remote close 또는 hardware watchpoint insertion 실패로 끝난다. `out/runtime_save_file_io_probe.json` 은 public save 를 임시 `SaveData/savedat1.dat` 로 두고 `WINEDEBUG=+file` file-I/O tracing 을 시도했지만 1/1 run 에서 `Hwanse2.exe` PID/key-buffer write 를 확보하지 못해 `inputTraceUsable=False` 로 남겼다. `out/runtime_save_file_io_strace_probe.json` 도 같은 public save 와 `strace` backend 로 1개 load-menu 후보 sequence 를 추적했지만 PID/key-buffer write 는 0/1이고 savedat 접근 line 은 0건이라 `inputTraceUsable=False` 로 남겼다. `out/runtime_save_file_io_strace_attach_probe.json` 은 Wine 을 정상 실행한 뒤 mapped `Hwanse2.exe` PID 에 strace 를 attach 하고 bounded `Down,Return` 후보에서 PID/key write 1/1, `inputTraceUsable=True`, matched savedat line 0건을 확보했다. 이는 해당 후보 window 의 file access 만 부정하며 전체 load-menu/route proof 는 아니다. 따라서 absent savedat line 은 load-menu 음성 증거가 아니라 backend/window 제한 증거로만 취급한다. 필요한 trace point 는 `0x0059e348` write watchpoint, opcode `0x24` mode1 read `0x0040c675`, frontier reader `0x00542b0c`, gate-time context base `0x005428c4` 이며, 이 trace 전까지 `map1_01a -> map2_02d` 는 blocked 로 유지한다.
- P8 next-action refs 는 이제 `out/runtime_trace_execution_probe.json` 도 직접 가리킨다. `route_investigation_queue`, `route_promotion_gate`, `completion_audit` verifier 가 이 direct ref 를 강제하므로, opcode `0x24` runtime producer trace blocker 를 볼 때 feasibility 요약뿐 아니라 canCaptureTraceNow, probe rows, qemu-i386 binfmt, relocation context, Wine prefix/gdb path, blocker list 를 원본 probe report 에서 바로 확인할 수 있다.
- 2026-06-09 runtime trace/predecessor field-entry 재확인: 현재 VM에서 `tools/probe_runtime_trace_execution.py` 를 다시 실행했지만 `canCaptureTraceNow=False`, blocker 6개, probe 18개로 남아 route watchpoint/breakpoint 증거는 확보하지 못했다. 이어 `tools/probe_runtime_predecessor_field_entry_sequence_scan.py` 도 재실행되어 22개 load-menu/field-entry sequence 를 다시 확인했지만 최종 selector 는 `1:0` 12개, `50:0` 2개, `8:0` 2개, `19:1` 6개이고 selector `2:0`/current root `0x00540714` hit 는 0이라 `diagnostic-only` 로 유지한다. `out/runtime_trace_execution_probe.*`, `out/runtime_trace_feasibility.*`, `out/runtime_predecessor_field_entry_sequence_scan.*`, `out/runtime_predecessor_route_attempt_context.json`, `out/predecessor_fill_external_proof_packet.*`, `out/route_promotion_gate.*`, `out/route_investigation_queue.*`, `out/completion_audit.*` 를 재생성했고 `tools/verify_web_assets.py` 는 8013 기준 통과하지만 `completion_audit achieved=false` 와 route promotion blocked 결론은 그대로다.
- 2026-06-09 predecessor field-entry probe CLI 보강: `tools/probe_runtime_predecessor_field_entry_sequence_scan.py` 는 이제 `--help`/`--list-sequences` 가 Wine runtime 을 실행하지 않고 즉시 종료하며, `--sequence-name`, `--sequence`, `--sequence-limit`, `--startup-wait`, `--hold`, `--gap`, `--final-wait`, `--out-dir` 로 22개 full sweep 대신 필요한 load-menu/field-entry sequence 만 짧게 재검증할 수 있다. `tools/verify_web_assets.py` 는 이 CLI marker 를 요구해 `--help` 가 다시 full runtime probe 를 시작하는 회귀를 막는다. 이는 P1 predecessor fill-site/order blocker 를 더 좁게 반복 조사하기 위한 probe tooling 보강이며, selector `2:0`/current root 실행 proof 가 새로 확보된 것은 아니다.
- `out/completion_audit.html`/`.md`/`.json` 은 이제 `docs/GOAL.md` 의 번호 작업과 현재 산출물을 직접 묶는 prompt-to-artifact checklist 를 포함한다. 체크리스트는 파일 인벤토리, 리소스 추출기, 첫 맵 재현을 complete 로 두지만, binary/event VM 해석, viewer/runtime 완성도, 원본 실행 흐름, Canvas runtime, 입력/이동/대화/전투 확장, primary route deliverable, 검증 command/gate 는 partial 로 남긴다. 특히 `tools/verify_web_assets.py` 통과는 완료 신호가 아니라 `completion_audit achieved=false`, hard route gate 실패, `map1_01a -> map2_02d` blocker 보존을 검증하는 신호로 기록한다.
- `out/runtime_save_file_io_strace_attach_load_candidates_probe.json` 은 같은 attached strace 방식으로 8개 load-menu 후보를 돌려 PID/key-buffer write 8/8, `inputTraceUsable=True`, matched savedat line 0건을 확보했다. 이는 covered 후보 window 의 file access 부정으로만 취급하며 전체 load-menu/route proof 는 아니다.
- `out/runtime_selected_pointer_poll.json` 은 WineDbg watchpoint 대신 `/proc/<pid>/mem` 로 selected-pointer global `0x0059de30` 을 20ms 간격으로 폴링하는 비디버거 fallback 이다. 8개 direct key-buffer sequence, 1550 sample 을 수집했지만 관측 selector 는 `8:0` 뿐이고 `2:0`/current root `0x00540714` 는 한 번도 잡히지 않았다. `out/runtime_key_sequence_prelude_probe.json` 은 input-path prelude 뒤 `accept`, `accept-accept`, `accept-down-accept` 를 다시 실행해 `8:0 -> 50:0` non-route selector 이동은 재현했지만, 여기서도 `2:0` 은 관측되지 않았다. `out/runtime_selected_pointer_prelude_poll.json` 도 같은 prelude 뒤 3개 sequence/491 sample 을 폴링해 `8:0,50:0` 만 관측했고 `2:0`/current root hit 는 0이다. `out/runtime_selected_pointer_long_poll.json` 은 `Return` 반복, `Down/Return`, `z` 조합 등 5개 긴 custom sequence/1928 sample 을 추가로 폴링했지만 `8:0,50:0` 만 관측했고 `2:0`/current root hit 는 0이다. `out/runtime_selected_pointer_late_poll.json` 은 로고 이후 검은 대기 화면까지 45초 기다린 뒤 1개 menu-explore sequence/1122 sample 을 폴링했지만 `8:0,50:0` 만 관측했고 `2:0`/current root hit 는 0이다. `out/runtime_route_watch_values_poll.json` 은 같은 late-start 입력에서 selected pointer 와 opcode24 watch byte 를 1123 sample 로 같이 읽었고, 여기서도 `8:0,50:0` 만 관측했으며 `opcode24Mode1Source=0x00`, `opcode24CurrentObjectIndex=0x00`, `opcode24RuntimeFlag=0x00/0x01` 로 남았다. `legacy savedata-load poll notes` 은 public captured save 를 임시 `SaveData/savedat1.dat` 로 둔 뒤 Enter/z/space/x 계열 8개 load-menu sequence/1353 sample 을 수집했지만 `8:0` 만 관측했고 `2:0`/current root hit 는 0이다. `legacy multislot savedata-load poll notes` 은 public real saves 를 `SaveData/savedat1.dat`..`SaveData/savedat3.dat` 로 staged 해 selector `1:0`, `0:0`, `22:0` 후보 6개/1266 sample 을 수집했지만 `8:0` 만 관측했고 staged public selector/`2:0`/current root hit 는 0이며 임시 SaveData 파일을 정리했다. `legacy multislot savedata case-alias poll notes` 은 같은 multislot staging 을 archive case alias 와 함께 반복했지만 6개 sequence/1263 sample 모두 `8:0` 만 관측했다. `legacy multislot savedata input-path/case-alias poll notes` 은 input-path prelude 뒤 같은 staged public saves/case alias 조건에서 6개 sequence/1265 sample 을 폴링했지만 selector `50:0` 만 관측했고 public selector hit=False, `2:0`/current root hit 0이다. `out/runtime_selected_pointer_synthetic_selector_2_0_input_path_case_alias_poll.json` 은 같은 경로에서 standalone synthetic selector `2:0` 파일을 staged 했지만 2개 sequence/374 sample 이 selector `8:0` 에 머물러 staged selector/current root/route hit 는 0이다. `out/runtime_selected_pointer_patched_public_selector_2_0_input_path_case_alias_poll.json` 은 같은 input-path/case-alias 경로에서 patched public-base diagnostic 을 staged 해 2개 sequence/375 sample 에서 selector `2:0,10:0` 과 current root hit 를 관측했다. 따라서 current load path 가 constructed `2:0` save-shaped 파일을 선택할 수 있음은 증명됐지만 standalone synthetic selector 는 non-promoting 이고 route pointer proof 로 세려면 여전히 captured selector `2:0` save 또는 watchpoint/runtime trace 가 필요하다.
- `out/save_selector_object61_stream_operands.html` 은 opcode `0x24` 가 쓰는 object `+0x61` consumer handler 들의 실제 route stream operand 를 확인한다. `map1_01a -> map2_02d` 에서 object handler opcode 는 5개, route operand row 는 12개이며 branch 가능한 row 는 `0x00542e74` opcode `0x2f` 1개뿐이다. 이 row 의 `dword [stream+4]` 는 `0x00001618` small scalar/scene id 로 `map2_16j.cns` 에 붙고, frontier leaf/reader/false target operand 는 0건이라 object `+0x61` 경로도 promotion 근거가 아니다.
- `out/save_selector_leaf_table_context.json` 은 current selector `2:0` 의 leaf table window 를 고정한다. root table pointer `0x005429dc` 근처에서 `0x00542ac0`/`0x00542ad4` 는 직접 leaf ref 로 나오고, reader-bearing `0x00542ae8` 은 `0x00542a04` wrapper 의 `0x00542a08` 에서 간접 참조된다. frontier leaf 가 current selector table window 에 속한다는 근거는 강화됐지만, wrapper 실행/selection index 와 strict source hotspot 이 없어 `map1_01a -> map2_02d` 는 blocked 유지다.
- `out/save_selector_leaf_table_context.*` 자체도 `evidenceRefs=4` 를 싣는다. refs 는 selector references, leaf streams, stream traces, script handler table 을 직접 가리키며, P6 next-action 과 completion audit normal evidence 가 같은 ref count 를 강제한다.
- `out/save_selector_leaf_index_space.*` 도 `evidenceRefs=3` 으로 leaf streams, stream traces, opcode `0x2c` corrected route-pair context 를 직접 가리킨다. P6 next-action 이 이제 이 report 를 직접 참조하므로 corrected non-negative route-pair reachability 와 raw negative reader-only selection gap 을 같은 blocker 체인에서 확인할 수 있다.
- `out/save_selector_leaf_table_global_context.*` 도 `evidenceRefs=2` 로 selector rows 원본과 `Hwanse2.exe` 의 leaf-table/descriptor dword 근거를 명시한다. 이제 `proofFound=False`, `leafTableGlobalProofFound=False`, `failedLeafTableGlobalGateIds=runtime-negative-wrapper-selection,nonnegative-route-pair-entry-reader-proof,selected-root-execution,strict-hotspot`, `missingEvidence=4` 도 직접 싣는다. wrapper/route-pair/index-source gap 이 공통으로 쓰는 current selector route rows `-13,-12,6,8` 과 frontier leaf negative-only 분류를 원본 입력까지 역추적할 수 있고, negative wrapper selection, non-negative reader proof, selected-root execution, strict hotspot 이 여전히 필요함을 한 줄에서 확인할 수 있다.
- `out/save_selector_route_pair_descriptor_context.json` 과 `out/save_selector_opcode2c_route_pair_context.json` 은 current root 의 non-negative entry `6`/`8` 이 `map1_01a`/`map2_02d` route-pair scene-list descriptor 를 갖고, reader-bearing frontier `0x00542b0c` 로 이어지는 `0x00542ae8` child 는 root-relative index `-12` 의 negative entry 에만 있음을 한 표에 고정한다. raw generic trace 는 opcode `0x2c` 에서 멈추지만 opcode `0x2c` 보정 trace 기준 reader 도달은 2/2 이다. 다만 geometry exit word hit 는 0개이고 runtime descriptor selection, reader branch target, strict source hotspot 이 아직 증명되지 않아 selector scene-list/control-flow adjacency 를 normal transition proof 로 승격하지 않는다. 두 report 모두 `proofFound=False`, failed gate 3개, `missingEvidence=3` 을 직접 싣고 route queue/blocker matrix/completion audit 은 이 값을 전파한다.
- Route-pair/opcode `0x2c` 리포트도 원본 입력 ref 를 직접 싣는다. `save_selector_route_pair_descriptor_context.json` 는 refs 4개(leaf index space, scene record sequence, stream traces, opcode `0x2c` context), `save_selector_opcode2c_route_pair_context.*` 는 refs 2개(`Hwanse2.exe`, route-pair descriptor context)를 갖고, verifier 는 두 report 의 ref path 와 `evidenceRefCount` 를 직접 검사한다.
- `out/save_selector_wrapper_descriptor_context.json` 은 `0x00542a04` wrapper 후보를 current root table entry 와 분리한다. `0x00542a04` 를 가리키는 table ref 는 `0x005429ac` 로 current root table pointer `0x005429dc` 앞에 있고, current root entry run `0x005429dc..0x00542a00` 안에는 wrapper ref 가 없다. `0x00542a08 -> 0x00542ae8` 은 descriptor child pointer 일 뿐 direct current-root table ref 가 아니므로, 이 경로 역시 promotion 근거가 아니다.
- `out/save_selector_opcode07_indexed_pointers.json` 은 selected-pointer global `0x0059de30` 을 갱신하는 opcode `0x07` 경로를 current `2:0` root 안에서 스캔한다. 33개 후보 row 중 `0x005429a8` leaf table, `0x00542a04` wrapper, `0x00542ae8` frontier leaf, `0x00542b0c` reader 를 직접 선택하는 row 는 0개이고, 유효 row 의 선택값은 script/action dword 로 분류된다. 따라서 opcode `0x07` direct-selection 경로도 promotion 근거가 아니다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_scene_list_context.json` 은 current frontier 주변 branch 를 scene-list/resource 관점으로 다시 분류한다. `0x00542b0c` branch target 은 `cara_01.cns` 이고, `map1_01a`/`map2_02d` 는 각각 `0x00542b44`/`0x00542bac` scene record 로 뒤따르므로 이 근거는 selector list adjacency 일 뿐 strict tile transition 이 아니다.
- `out/save_selector_scene_record_sequence.html` 은 current selector `2:0` leaf stream 3개를 field-map scene record 단위로 다시 자른다. 세 stream 모두 `map1_01a -> map2_02d` scene record 가 인접하지만 geometry exit word hit 는 0개이고 strict hotspot row 도 없으므로, 이 인접성은 normal route proof 가 아니라 selector scene-list adjacency 로 blocked 유지다.
- `out/save_selector_scene_adjacency_index.json` 은 전체 save-selector field-map scene-record adjacency 를 strict event transition/review 와 대조한다. selector leaf 322개, field-map ref 663개에서 adjacent occurrence 341개와 unique directed pair 77개가 나오지만 strict event edge 45개 및 confirmed review edge 1개와 겹치는 adjacent pair 는 각각 0개다. `map1_01a -> map2_02d` 는 selector `2:0` leaf 3개에서만 반복되는 selector-adjacency-only pair 이며 strict/confirmed backing 이 없으므로, scene-list adjacency 를 normal transition proof 로 승격하지 않는다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- P3 증거 전파 패스에서는 resource/scene-list gate 의 원본 ref 를 queue/gate/audit 산출물에 필수로 고정했다. priority 3 action 은 `out/save_selector_scene_list_context.json`, `out/save_selector_frontier_reader_branch_context.json`, `out/save_selector_frontier_payload_shape.json`, `out/save_selector_scene_adjacency_index.json` 의 핵심 필드를 직접 참조하며, verifier 는 scene-list/resource branch, image-rect payload, selector-adjacency-only 판정이 빠지면 실패한다.
- P3 resource/scene-list gate 도 top-level proof/missing-gate 형식으로 맞췄다. `out/save_selector_scene_list_context.*` 는 `proofFound=False`, `failedSceneListGateIds=resource-branch-not-field-map,selector-adjacency-only,strict-hotspot-missing`, `missingEvidence=3` 을 싣고, frontier reader/payload/scene adjacency 리포트도 각각 `failedFrontierReaderGateIds`, `failedFrontierPayloadGateIds`, `failedSceneAdjacencyGateIds` 와 `missingEvidence=3` 을 직접 노출한다. route queue/gate/blocker matrix/completion audit 은 이 값을 전파해, `0x00542b0c` resource branch, image-rect payload, selector-only adjacency 가 왜 normal route proof 가 아닌지 한 줄로 확인할 수 있다.
- P3 resource/scene-list gate 의 원본 입력 ref 도 각 report 에 직접 고정했다. `save_selector_scene_list_context` 는 refs 3개(`Hwanse2.exe`, frontier branches, scene manifest), frontier reader 는 refs 4개(scene-list context, branch selector equation, scene payload context, opcode `0x2c` route-pair context), frontier payload 는 refs 4개(`Hwanse2.exe`, CNS payloads, maps.js, frontier reader context), scene adjacency 는 refs 3개(selector references, event transitions, transition reviews)를 싣고, route queue/gate verifier 는 priority 3 action 이 `evidenceRefs`/`evidenceRefCount` 를 보존하지 않으면 실패한다.
- `out/save_selector_current_writer_paths.json` 은 current selector `2:0` 안의 selection/current writer path 를 고정한다. current route root `0x00540714` 에는 writer 4개와 selected-pointer store `0x0054248c`, activation store `0x0054246c` 가 있지만 모두 current root 내부 경로이며, source/predecessor 에서 current root 로 들어오는 selected-root execution ref 가 없어 `blocked-current-internal-only` 로 유지한다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/save_selector_current_writer_paths.json` 도 row-level `evidenceRefs=2` 를 싣는다. refs 는 current frontier root writer scan 과 `Hwanse2.exe` 의 writer stream/opcode handler/activation dword 근거를 직접 가리키며, P6 next-action 과 blocker matrix/current-writer normal evidence 가 같은 ref count 를 전파한다.
- `out/map_exit_candidates.html`/`.md`/`.json` 은 selector-linked source map 의 통행 가능 connected component 가 맵 가장자리에 닿는 지점을 geometry-only 후보로 묶는다. 현재 `map1_01a` 는 상단 `18,0`, 하단 `16,47`, 좌측 `3,14`, 우측 `34,19` 를 review URL 로 제공하지만 모두 `manual-review-only` 이며, strict source coordinate/hotspot 이 확인되기 전까지 normal transition 근거가 아니다. 웹 런타임은 상세 JSON 대신 `out/map_exit_candidates_runtime.js` 의 작은 인덱스만 읽고, `trialTransitions=mapExitCandidates` 또는 후보 진행용 `trialTransitions=routeAssist` 에서 후보 타일을 exit trial 로 표시한다. 이 모드의 후보는 `transitions` 드롭다운, `M`/`Shift+M`, 모바일 이전/다음 버튼으로 순회 가능하다. 실제 맵 경계에 붙은 `auto` 후보(`edgeDistance=0`)는 바깥 방향으로 한 번 더 이동하려 할 때 임시 전환이 실행되고, 주황색 `manual` 안쪽 edge-band 후보는 수동 테스트로만 남긴다. 임시 전환 spawn 은 source exit 별 target hint 를 우선 사용한다. 이 hint 는 target 맵의 반대쪽 side, `autoTrigger`, 통행 가능 여부, edge distance, side projection 을 점수화한 reciprocal trial-spawn 후보이며, 여전히 normal transition 승격 근거는 아니다.
- `out/original_collision_route_audit.html`/`.md`/`.json` 은 위 네 geometry 후보를 `collisionMode=originalLayer1Flags` 기준으로 재검사한다. 원본 `0x0042449c` map loader 가 CNS layer1 flag grid 를 `0x0058d7d0` 에 복사한다는 근거를 route 후보 링크에 붙였고, `map1_01a` source 후보는 3/4개, `map2_02d` target spawn hint 는 4/4개가 원본 layer1 footprint 기준 standable 로 나온다. 하지만 이 결과는 collision diagnostic 일 뿐 strict source hotspot, selected-root execution proof, 실제 selector `2:0` save, runtime trace/equivalent proof 를 대체하지 못하므로 promotion status 는 `diagnostic-only` 다.
- 같은 original collision audit 도 proof/missing/ref 형식으로 맞췄다. `out/original_collision_route_audit.*` 는 `proofFound=False`, `failedOriginalCollisionRouteGateIds=strict-source-hotspot,selected-root-execution,real-selector-2-0-savedata,runtime-trace-or-equivalent-control-flow`, `missingEvidence=4`, `evidenceRefs=3` 을 직접 싣고, route queue/gate/blocker matrix/completion audit 은 이 값을 전파해 원본 layer1 collision 재검사가 왜 strict hotspot/save/runtime proof 를 대체하지 못하는지 한 줄로 확인하게 한다.
- `out/map1_01a_edge_trigger_gap.json`/`.md` 은 위 후보가 원본의 일반 edge/boundary trigger 로 승격될 수 있는지 별도 점검한다. source boundary 후보는 top `18,0` 과 bottom `16,47` 2개이고 collision helper `0x004319f8` 의 boundary check 는 direction latch fallback 을 쓴 뒤 actor overlap loop `0x00431ca6` 로 떨어진다. actor controller 의 collision helper call 은 20개지만 helper/controller 범위에서 map loader, script runner, selector table, selected pointer `0x0059de30`, current root `0x00540714`, `map1_01a`/`map2_02d` 문자열 직접 참조가 모두 0건이다. direction latch `0x00574533` 의 `.text` direct ref 79개 전체도 주변 window 에 transition rel hit 0건/route immediate 0건이고, actor-controller caller 1개와 collision-helper caller 20개의 ±192 byte caller-window scan 도 각각 transition rel/route immediate hit `0/0` 이라 generic edge trigger proof 는 `blocked-generic-edge-trigger-unproven` 으로 남는다.
- 같은 edge trigger gap 은 `.text` 전체 direct-reference scan 도 함께 고정한다. 전역 map-loader/script-runner/selector-table rel hit 는 `0/4/0` 이고 selected pointer/current root/source string/target string immediate 는 `6/0/0/0` 이다. 전역 script-runner call 4개 주변 ±192 byte window 도 selected pointer/current root/source string/target string immediate 0건, map-loader/selector-table rel hit 0건이며 actor-controller/collision-helper range 안의 call 도 0건이다. 전역 selected-pointer immediate 6개 주변 ±192 byte window 역시 current root/source string/target string/map-loader/script-runner/selector-table hit 가 모두 0건이므로 helper/controller 창 밖에서도 `map1_01a -> map2_02d` edge transition direct branch 근거가 없다. 이번 pass 는 직접 dword 밖의 `abs16-low`, `signed-rel16-site-plus2`, `signed-rel32-site-plus4` encoded target scalar 까지 훑어 edge handler/local/callgraph `0/0/0/0/0` 을 확인했고, global contrast 의 4건은 모두 script-runner rel32 scalar 이며 route proof/selected-pointer/promoting 0건이라 `edge-encoded-route-target-scalars-nonpromoting` 으로 분리했다. 이 caller/window/encoded 값은 `route_investigation_queue`, `route_promotion_gate`, `route_blocker_evidence_matrix`, `completion_audit` 로 `scriptRunnerWindows=4/0/0/0`, `edgeScriptRunnerWindows=4/0/0/0`, `selectedPointerWindows=6/0`, `edgeSelectedPointerWindows=6/0`, `callerWindows=1/0/0;20/0/0`, `edgeCallerWindows=1/0/0;20/0/0`, `edgeEncoded=0/0/0/0/0;0/0/0/0/0;0/0/0/0/0;4/4/0/0/0` 형태로 전파된다.
- `out/map1_01a_tile_hotspot_pattern_contrast.html`/`.json` 은 confirmed `map1_02b -> map1_01a` hotspot review 와 현재 `map1_01a -> map2_02d` 후보 타일을 같은 originalLayer1Flags 기준으로 대조한다. confirmed 쪽은 `0x00503350` event record 와 confirmed review 2개/rejected 22개가 있지만, current 쪽은 source 후보 4개 중 3개가 standable, target spawn 4/4 standable, layer1 low nibble match 4/4 이어도 strict event point 0개/transition review row 0개라 tile signature 만으로 hotspot 을 확정하지 않는다. 이 report 도 `proofFound=False`, `failedTileHotspotPatternGateIds=4`, `missingEvidence=4`, `evidenceRefs=4` 를 직접 싣고, route queue/gate 가 P5 ref 에서 같은 필드를 요구한다.
- `out/map1_01a_exit_target_ranking.json` 은 `map1_01a` 출구 후보 4개를 target hint, reciprocal target exit, coordinate scan, routeAssist 순서로 다시 묶는다. `map2_02d` 에 대해서는 top `18,0` 과 bottom `16,47` 이 자동 edge 테스트 대상이고 left/right 는 수동 후보지만 coordinate-promotable exit 는 0개다. scene-list outgoing 후보도 `map1_02b` 2회, `map2_02d` 3회뿐이고 둘 다 strict/confirmed backed 0건의 selector-adjacency-only 라 대체 outgoing proof 로 승격하지 않는다. confirmed `map1_02b -> map1_01a` 리뷰 2건은 entry proof 로만 분리되어, outgoing `map1_01a -> map2_02d` 승격에는 strict source hotspot 또는 runtime/control-flow proof 가 계속 필요하다. 이 ranking report 도 `proofFound=False`, `failedExitTargetRankingGateIds=4`, `missingEvidence=4`, `evidenceRefs=5` 를 포함해 geometry/selector-adjacency-only 판단이 promotion proof 가 아님을 ref 자체에서 표시한다.
- `out/route_blocker_evidence_matrix.html`/`.md`/`.json` 은 현재 blocker `map1_01a -> map2_02d` 의 증거를 geometry exit, original collision flags, generic edge trigger, strict hotspot, selector merge, selector root ref table-only context, wrapper execution gap, scene adjacency index, 실제 savedat, 원본 save path, runtime trace, selected-pointer choke point, current writer path, selected-root execution gap 으로 한 번에 묶는다. `out/route_promotion_gate.html` 은 같은 blocker 의 hard gate 를 strict source/tile hotspot, real selector `2:0` save, selected-root execution proof, runtime trace/equivalent proof 로 압축해 모두 false 일 때 normal route 승격을 막는다. `out/route_investigation_queue.json` 도 이제 `promotionStatus=blocked`, `promotionAllowed=False`, failed gate ids `strictSourceHotspot,tileHotspotConfirmation,realSelector20Savedata,selectedRootExecution,runtimeTraceOrEquivalent`, hard missing evidence `strict source coordinate,tile hotspot confirmation,real selector 2:0 captured savedata,selected-root execution ref,runtime trace/equivalent selected-root proof` 를 직접 보존한다. 원래 routeAssist/frontier blocker 의 missing evidence 3개는 `frontierMissingEvidence` 로 남기고, top-level `missingEvidence` 는 promotion gate 와 같은 5개 hard gate 목록으로 확장해 queue 만 봐도 실제 savedata/runtime trace blocker 를 놓치지 않게 했다. `out/route_investigation_queue.json` 과 `out/route_promotion_gate.json` 의 각 `nextActions` 는 이제 `evidenceRefs` 를 포함해 우선순위 1 predecessor fill-site proof, 우선순위 5 strict hotspot, 우선순위 8 opcode `0x24` runtime trace 같은 작업이 어느 JSON 필드에 의해 막혔는지 직접 가리킨다. `out/route_promotion_gate.json.strictSourceHotspotCandidateRows` 는 top `18,0`, bottom `16,47`, left `3,14`, right `34,19` 후보 4개를 auto/boundary 플래그와 `routeAssistUrl`/`targetReviewUrl` 까지 보존한다. `out/completion_audit.json` 의 `confirmedRouteBlockers[0].routePromotionNextActionEvidenceRefs` 와 `routePromotionStrictSourceHotspotCandidateRows` 도 같은 refs/후보 행을 보존해 completion audit 만 봐도 다음 증거 파일과 후보 리뷰 URL 을 추적할 수 있다. 현재 분류는 geometry exit `trial-only`, original collision flags `diagnostic-only`, generic edge trigger `blocked-generic-edge-trigger-unproven`, strict hotspot `missing`, selector merge `open`, selector root refs `table-only-no-execution`, wrapper execution gap `blocked`, scene adjacency index `selector-adjacency-only`, real savedata `missing-current-selector`, original save path `static-known-input-path-unproven`, runtime trace `blocked-by-vm`, selected pointer `trace-needed`, current writer paths `blocked-current-internal-only`, selected-root execution gap `blocked-no-execution-ref` 이며 promotion allowed 는 false 다. selector root ref 행은 route selector roots 가 table-only pointer chain 이고 `.text` refs, predecessor-to-current root ref, route order proof 가 모두 없음을 고정한다. selected-root execution gap 행은 base `1550`, prelude `491`, long `1928`, late-start `1122` selected-pointer poll sample, 1123 sample route watch-value poll, public-save `SaveData/savedat1.dat` load-menu poll 1353 sample, public real saves multislot load-menu poll 1266 sample, case-alias multislot poll 1263 sample, input-path case-alias multislot poll 1265 sample, predecessor direction sweep poll 3380 sample, patched public-base selector `2:0` diagnostic poll 375 sample 을 같이 표시한다. input-path case-alias poll 은 observed selector `50:0` 및 observed public selector 없음으로 non-route 상태를 보이고, predecessor direction sweep 은 observed selector `50:0,19:1,1:0` 및 observed public selector `1:0` 으로 public save load path 일부를 증명하며, patched diagnostic 은 `2:0,10:0` 과 current root 를 관측한다. `out/runtime_patched_selector_followup_context.json` 은 그중 sampled `2:0 -> 10:0` 이동을 target-side address-adjacent alias 로 따로 분류하지만, constructed bytes/`map1_01a` 미포함/실행 bridge 부재 때문에 non-promoting 으로 유지한다. 그러나 constructed bytes 이므로 selected-root execution proof 에 넣지 않아 `anyPollRoute=False` 로 남긴다. promotion gate 는 selected-root subgate 도 직접 표시해 save-loader `missing-current-selector`, static refs `table-only-no-text-ref`, dispatch `static-slice-only`, opcode paths `no-non-current-producer`, writer `current-internal-only`, runtime `no-real-selector-2:0-observed`, diagnostic `diagnostic-excluded` 상태를 completion audit 과 같은 문자열로 검증한다. saveLoadPoll 도 관측 selector 가 `8:0` 뿐이고 multiSaveLoadPoll/caseAliasMultiSaveLoadPoll 역시 staged public selector `1:0`/`0:0`/`22:0` 대신 `8:0` 만 관측했으며, inputPathCaseAliasMultiSaveLoadPoll 은 publicHit=False/route=False 이고 predecessorDirectionSweepPoll 도 publicHit=True/route=False 이며 watch-value poll 도 `opcode24Mode1Source=0x00`, `opcode24CurrentObjectIndex=0x00`, `opcode24RuntimeFlag=0x00/0x01` 또는 all-zero 상태라 diagnostic-only 이다. 다음 필요 증거는 captured selector `2:0` save 또는 `0x0059de30 == 0x00540714` runtime trace, strict `map1_01a` source trigger, selector merge/control-flow proof 로 고정한다. 같은 페이지는 `route_investigation_queue.html`, `save_selector_wrapper_execution_gap.html`, `save_selector_selected_root_execution_gap.html`, `save_selector_real_savedata_evidence_gap.html`, `runtime_save_path_context.json`, `savedata_slot_scan.html`, `map1_01a_hotspot_gap.html`, `runtime_trace_feasibility.html`, 브라우저 `savedatScan=1` 링크를 함께 제공해 blocker 확인 후 다음 증거 페이지로 바로 이동하게 한다.
- 이번 verifier 보강으로 priority 1-9 의 next-action ref 전체가 `route_investigation_queue`, `route_promotion_gate`, `completion_audit` 세 산출물에서 빠지면 실패하도록 고정됐다. P4 savedata scan/selected-pointer usage, P9 strict target-link gap, P3 resource/scene-list gate 도 다른 hard-gate ref 와 같은 수준으로 audit 에 보존된다.
- `route_promotion_gate` 와 `completion_audit` 의 next-action 행은 이제 `task` 뿐 아니라 `why` 문장도 유지한다. 특히 P1 predecessor fill-site execution/order 와 P8 opcode `0x24` mode1 runtime producer trace 는 refs 목록만이 아니라 왜 다음 증거인지까지 audit JSON/MD/HTML 에 남으므로, 다음 세션에서 action label 없이 ref path 만 보고 재해석하는 일을 줄인다.
- 이어서 `completion_audit` blocker row 도 `routePromotionFailedGateIds` 와 `routePromotionMissingEvidence` 를 직접 싣도록 맞췄다. 이제 audit JSON/MD/HTML 만 열어도 failed gate ids `strictSourceHotspot,tileHotspotConfirmation,realSelector20Savedata,selectedRootExecution,runtimeTraceOrEquivalent` 와 hard missing evidence 5개가 `route_promotion_gate` 원본과 같은 순서로 보이며, verifier 가 두 목록의 누락을 잡는다.
- 같은 gate 는 opcode `0x24` mode1 source/runtime producer gap 도 직접 노출한다. Mode1 source `0x0059e348` 은 direct read 1건뿐이고 direct write 0건이며, 바로 아래/위 direct-write byte 는 `0x0059e347`/`0x0059e34a` 라 `mode1DirectWriteHole=True` 로 남는다. covering/index/address/static producer 는 `0/0/0/0`, static 값은 zero-filled `0x00` 이며 savedata-backed 도 아니다. Patched `2:0` diagnostic 210/374 sample 에서 mode1/runtimeFlag/currentObject 가 모두 `0x00` 으로 안정적이지만 diagnostic-only 이고, runtime flag `0x0059e34d` 는 read 12/write 0/flag-one required 라 producer trace 없이는 promotion 은 blocked 다.
- `out/route_assist_frontier.html`/`.md`/`.json` 은 현재 confirmed route blocker 만 따로 모은 좁은 수동 테스트 인덱스다. `map1_01a -> map2_02d` 의 네 출구 후보(top `18,0`, bottom `16,47`, left `3,14`, right `34,19`)와 target spawn hint 를 `trialTransitions=routeAssist&transitionTarget=map2_02d` 링크로 바로 열 수 있어, 전체 transition dropdown 을 거치지 않고 막힌 루트만 확인할 수 있다. 이 리포트도 `trial-only` 이며 normal route 승격 근거는 아니다.
- `web/index.html` 은 priority map-exit 후보가 있는 맵에서 `routeFrontierSelect` 를 표시한다. 이 선택지는 기존 전체 transition dropdown 과 별도로 현재 blocker 의 trial-only route assist 후보만 보여주고, 선택 시 `trialTransitions=routeAssist`, `transitionTarget`, `startTile`, `focusTile` 쿼리를 함께 갱신해 같은 후보를 바로 공유/재현할 수 있게 한다. `out/playable_progress_runtime.js` 는 confirmed reachable map 과 save-selector candidate reachable edge 의 작은 런타임 인덱스를 제공하고, 게임 화면의 `보조` 버튼은 priority route frontier 또는 confirmed route 밖 candidate-only reachable 맵에서 첫 후보 출구로 바로 포커스/워프해 도구 패널 없이도 막힌 route 를 이어서 시험할 수 있다. 상단 `루트` 링크는 `out/web_playtest_route.html` 을 열고, `근거` 링크는 현재 blocker 의 `out/route_blocker_evidence_matrix.html` 을 바로 열어 trial route 와 promotion blocker 를 함께 확인하게 하며, `목표` 링크는 `out/completion_audit.html` 을 열어 `/goal` completion audit 의 partial/missing 항목을 바로 확인하게 한다. `세이브` 링크는 `savedatScan=1` 로 `SAVEDATA/savedat1-9.dat/.zip` route evidence 검사를 바로 실행한다. WebKit smoke 는 이 흐름으로 `map1_01a -> map2_02d` 후보 전환 뒤 다시 `보조` 버튼을 눌러 `map2_18d:46,0` frontier 를 고르고, 조이스틱 위 입력으로 `map2_18d` 에 실제 진입하는지 확인한다. routeAssist 상태에서는 이동 후 URL 동기화도 사용자가 명시적으로 선택한 `transitionTarget` 만 유지하고, HUD/링크 계산 중 자동으로 고른 다음 후보는 URL 에 섞지 않는다. 일반 화면과 overview 의 map-exit overlay 는 선택된 target/focus 후보를 더 굵게 표시하고 target 이름을 label 로 보여준다.
- `out/web_playtest_route.html`/`.md`/`.json` 은 브라우저에서 바로 열어보는 루트 인덱스다. confirmed start `map1_02b@11,12`, `trialTransitions=routeAssist` 시작 URL, blocker `map1_01a -> map2_02d`, 네 candidate exit, post-blocker `map2_02d -> map2_18d` 후보, evidence matrix 링크, 새 캡처 save 검사 URL 예시 `savedatUrl=../SAVEDATA/savedat2.dat`, `savedatUrl=../SAVEDATA/savedat2.zip`, `savedatScan=1` 를 묶어 긴 transition dropdown 을 거치지 않고 현재 playtest 경로를 재현하게 한다. `savedatScan=1` 은 `SAVEDATA/savedat1.dat`..`savedat9.dat`, `SAVEDATA/savedat1.zip`..`savedat9.zip`, 원본 케이스 `SaveData/` alias 를 함께 검사한다. 플레이 화면에 `.dat`/`.zip` 을 드래그 앤 드롭해도 같은 `loadSavedatFile` 파서와 route-evidence 판정을 타며 `window.HWANSE_LAST_SAVEDAT_DROP` 에 마지막 selector/route verdict 를 남긴다. RouteAssist path sample 의 open 링크는 `routeGoal=<target>` 을 포함해, 링크로 들어간 뒤 상단 `다음`/`후보`/`진입` 버튼 흐름으로 목표 맵까지 따라갈 수 있다. WebKit smoke 는 이 버튼 흐름이 confirmed `map1_02b -> map1_01a`, trial-only `map1_01a -> map2_02d` blocker 후보 포커스/진입, post-blocker `map2_02d -> map2_18d` 후보 포커스/진입까지 이어지는지 확인한다. `tools/verify_route_guide_browser.py` 는 별도로 `out/web_playtest_route.html` 자체와 `routeGoal=map2_18d` 링크가 실제 게임 런타임으로 열리는지 확인해 `out/route_guide_browser_smoke.*` 로 남긴다. 같은 문서는 `save_selector_real_savedata_evidence_gap.html` 과 `savedata_slot_scan.html` 을 링크하고, route promotion 에 필요한 save byte `0x0002=0x02`, `0x0003=0x00`, selected pointer `0x00540714` 조건을 바로 표시한다. 2026-06-08 부터는 `route_promotion_external_proof_handoff.json` 의 `Required External Inputs` 도 route index JSON/MD/HTML/runtime JS 에 전파해 `real-selector-2-0-save`, `normal-route-runtime-trace`, `strict-source-hotspot` 의 current state, accepted signal, refresh command 를 플레이 테스트 페이지에서 바로 확인한다. 같은 route index 는 `completion_audit.html` 도 직접 링크해 top-level `achieved=false`, prompt-to-artifact checklist, partial/missing requirements 를 route playtest 표면에서 함께 확인한다. `/web/index.html` 의 `루트` 링크도 이 인덱스를 바로 연다. 이 인덱스도 `routeAssist-required` 상태이며 normal route 승격 근거는 아니다.
- route index 의 savedata section 도 `validRealCandidatesAllBlocked=True` 와 real candidate block reason counts 를 표시해, 브라우저에서 플레이 경로를 확인하는 중에도 공개 save 6개가 selector byte pair/current root/route-pair gate 에서 막혔음을 바로 확인할 수 있다.
- `out/map_exit_coordinate_refs.html`/`.md`/`.json` 은 geometry-only 출구 후보 좌표를 EXE packed-coordinate 관점으로 다시 스캔한다. 현재 `map1_01a -> map2_02d` 의 우측 `34,19` 후보는 `xy=0x00130022` 데이터 hit 1건만 있고 table window 를 가리키는 `.text` 참조가 없어 `coordinate-like-hit-without-table-text-ref` 로 유지한다. 상단 `18,0` 처럼 `.text` immediate 로도 많이 나타나는 값은 too-generic literal 로만 보고, bottom `16,47` 은 exact packed hit 이 없다. 이 리포트는 promotion gate 가 아니라 strict hotspot 을 찾기 위한 음성/진단 근거다.
- 같은 coordinate false-positive 보조 리포트들도 top-level proof/missing-gate 형식으로 맞췄다. `out/map_exit_coordinate_refs.*` 는 `proofFound=False`, `failedMapExitCoordinateRefGateIds=strict-source-coordinate-owner,table-text-reference,target-map-control-path,manual-review-promotion-proof`, `missingEvidence=4`, `evidenceRefs=6` 을 싣고, `out/map1_01a_exit_byte_coordinate_scan.*` 은 `failedExitByteCoordinateGateIds=strict-source-target-byte-owner,target-spawn-strict-byte-owner,axis-or-span-sequence-owner,runtime-trigger-proof`, `missingEvidence=4`, `evidenceRefs=5` 를 싣는다. `out/map1_01a_exit_cns_payload_scan.*` 도 `failedExitCnsPayloadGateIds=separate-cns-coordinate-payload,outside-structured-tilemap-hit,strict-source-target-cns-owner,runtime-trigger-proof`, `missingEvidence=4`, `evidenceRefs=3` 을 싣고 P5 next-action refs/verifier 가 세 리포트의 proof/missing/ref-count 필드를 강제한다.
- `out/map1_01a_exit_coordinate_context.json` 은 우측 `34,19` 의 유일한 `xy=0x00130022` hit 를 분리해 해석한다. hit `0x004f9460` 은 field map 없는 selector `24:0` root `0x004f8dd8` 안의 low opcode `0x22` save-selector script word 이고 owner linked CNS 는 `cara_at1.cns` 뿐이다. 이제 이 report 도 `proofFound=False`, `failedExitCoordinateContextGateIds=strict-source-coordinate-owner,source-field-map-owner,text-or-code-reference-to-hit,target-map-control-path`, `missingEvidence=4`, `evidenceRefs=3` 을 직접 싣는다. 따라서 이 byte sequence 는 strict `map1_01a` coordinate table 이 아니며 transition promotion 근거가 아니다.
- `out/map1_01a_exit_coordinate_variant_scan.json` 은 우측 `34,19` 후보와 나머지 3개 출구 후보를 `x,y`, `y,x`, one-based, outside tile, `tile*16`, runtime pixel origin(`tile*16-16`), runtime pixel center(`tile*16+8`), outside pixel, span corner/bounds 좌표 변형으로 넓혀 스캔한다. `x,y=0x00130022` 는 `cara_at1` descriptor script hit 1건뿐이고, `y,x=0x00220013` 는 current selector root 안에 2건 있으나 low opcode `0x13`/offset `0x22` 의 save-selector selection opcode row 로 해석된다. 우측 runtime pixel origin 은 hit 0건이고 center `y,x=0x02280138` 은 `.data` 1건/current-root 0건이라 strict source hotspot 증거가 아니다. span corner scalar 는 current root hit 10건이 있지만 모두 selector script word 이고 min/max span sequence hit 는 0건이므로, 영역 테이블 근거도 아니며 blocked 유지다.
- `out/map1_01a_exit_byte_coordinate_scan.json` 은 네 출구 후보를 byte-sized `x,y`/`y,x`/one-based/outside 좌표와 axis/span byte sequence 로 다시 훑는다. byte-pair scans 24, sequence scans 16, byte-pair hits 5021, sequence hits 0, strict source-target byte hits 0, strict-event-other hits 22, current selector-root byte collisions 66, text-code byte collisions 233 이며 `strictByteCoordinateEvidenceFound=False`/promotion blocked 다. 우측 `34,19` 의 tile byte `x,y`(`22 13`) hit 는 0건이고 `y,x`(`13 22`) hit 는 1건뿐이라 strict `map1_01a` coordinate table 로 승격하지 않는다.
- `out/map1_01a_exit_cns_payload_scan.json` 은 같은 네 후보를 압축해제된 `extract_fld/map1_01a.cns` payload 자체에서 byte/word/packed coordinate 와 byte/word axis/span sequence 로 검사한다. source CNS 는 header 4 bytes + layer0/layer1 각각 1776개 u16 tile index 로만 구성된 37x48 tilemap(7108 bytes)이고, scan count 는 byte/word/packed `24/24/24`, byte/word sequence `16/16` 이다. hit 는 byte/word/packed `8/3/3`, sequence 0, header/layer/outside `0/14/0` 으로 전부 layer tile-index collision 이며 `strictCnsCoordinateEvidenceFound=False`/promotion blocked 다.
- `out/map1_01a_hotspot_gap.html` 은 strict source hotspot 부재를 target context 와 함께 고정한다. `map1_01a` 좌표 row 는 strict event/broad coordinate/extraction gap 어디에도 없고, `map2_02d` target context 5개는 모두 selector-only scene-list cluster 이며 strict event-linked context 는 0개다. current cluster `0x00542b44..0x00542e74` 는 `map1_01a` 와 여러 `map2_*` record 를 함께 나열하므로 selector adjacency 를 normal transition 으로 승격하지 않는다.
- `out/map1_01a_scene_payload_context.json` 은 current selector-only cluster 의 `0x00542b44` scene window 에 있는 scene-local payload pointer 를 별도로 해석한다. `0x0053f4ac`, `0x0053f4fc`, `0x0053f85c` 는 in-bounds `map1_01a` coordinate table 이 아니고 sampled window `.text` refs 도 0건이라 sprite/rect-like resource payload 로 남긴다. 이 근거는 `0x00542b44 -> 0x00542bac` adjacency 를 normal transition 으로 승격하지 않는 추가 gate 다.
- `out/map1_01a_resource_ref_scan.json`/`.md` 은 `map1_01a.cns` 와 `map2_02d.cns` 를 직접 가리키는 EXE resource reference 10개를 넓은 window 로 스캔한다. current frontier reference `0x00542b44` 는 `map2_02d` 를 같은 selector-only scene list 안에 포함하지만, 주변 point-table-like payload 163개 중 geometry route-exit sample 과 일치하는 후보는 0개라 strict source-target candidate 도 0개다. 추가 classification 은 전체 후보를 `sentinel-0x003f-singleton` 103개, `resource-size-singleton` 28개, 기타 short/script-shaped non-route run 으로 분리하고, current frontier 는 `sentinel-0x003f-singleton:16`, `resource-size-singleton:2`, route hit 0 으로 고정한다. 따라서 resource reference 전수 스캔도 `map1_01a -> map2_02d` 를 normal transition 으로 승격하지 않는다.
- `out/map1_01a_record_pattern_contrast.json` 은 confirmed `map1_02b -> map1_01a` 전이 패턴과 current `map1_01a -> map2_02d` frontier 를 나란히 비교한다. confirmed 쪽은 `0x005032d8..0x00503350` strict event-linked cluster, event record `0x00503350`, 24개 raw point, 2개 confirmed review tile 을 갖지만, current frontier 는 `0x00542b44..0x00542e74` selector-only cluster, event record 0개, save-selector ref 34개, route-exit point candidate 0개, geometry exit word hit 0개이며 branch target 도 `cns:cara_01.cns` resource gate 라서 confirmed-like pattern 이 아니다.
- `out/map1_01a_strict_target_link_gap.json` 은 `map1_01a -> map2_02d` 의 strict source-target link 부재를 별도로 고정한다. `map1_01a` 를 포함한 strict cluster 는 `0x005032d8..0x00503350` 하나뿐이고, 이 cluster 의 event source 는 `map1_02b`, event link 는 `map1_01a` 라서 incoming-only 이다. `map1_01a` 에서 시작해 `map2_02d` 로 가는 direct strict event transition 은 0개이고, `map2_02d` 를 포함한 target context 5개는 모두 selector-only cluster 이다. 이 중 source 와 target 을 함께 담는 cluster 는 current frontier `0x00542b44..0x00542e74` 하나뿐이며, 그 안에서도 source outgoing 10개/target incoming 10개/전체 route-pair 110개 중 1개 조합이라 strict adjacent/source cluster link 로 승격되지 않는다.
- P5 증거 전파 패스에서는 strict source/hotspot blocker 의 후보 행도 상위 산출물에 보존한다. priority 5 action 은 strict source hotspot candidate summary 4개, consolidated evidence row 12개, remaining proof 3개, strict hotspot review candidate row 4개, exit ranking rows `4/1/2/2/3`, edge-trigger candidate row 4개 및 direct-call graph evidence 를 직접 참조한다. `route_promotion_gate` 와 `completion_audit` 도 같은 row count 를 포함해, strict source coordinate/tile hotspot 이 아직 없는 이유를 count-only 요약이 아니라 후보 행과 review/edge/ranking 행으로 추적하게 한다.
- 같은 exit ranking 증거는 이제 blocked/return target 도 구조화해 `map2_02d/map1_02b` 와 selector occurrence `3/2` 를 `out/route_promotion_gate.*` 및 `out/completion_audit.*` blocker row 에 보존한다. 따라서 `map1_01a -> map1_02b` return 후보 역시 selector-adjacency-only 이고 strict/confirmed-backed outgoing 이 0개라 대체 normal transition proof 가 아니라는 점을 audit JSON 만으로 확인할 수 있다.
- 같은 P5 action 의 `evidenceRefs` 는 이제 `map_exit_coordinate_refs`, `map1_01a_exit_coordinate_context`, `original_collision_route_audit`, `map1_01a_strict_event_tile_signature_scan` 도 직접 가리킨다. route queue 의 본문 요약도 coordinate ref/context, original collision diagnostic, strict event tile signature 의 non-promoting 값을 직접 표시하고 `route_promotion_gate`/`completion_audit` verifier 역시 같은 refs 를 강제하므로, queue/gate/audit 만 열어도 strict source/tile hotspot blocker 를 확인하고 원본 증거 파일로 이동할 수 있다.
- P9 증거 전파 패스에서는 strict target-link blocker 도 cluster row 자체를 다음 action/audit 에 보존하도록 고정했다. priority 9 action 은 `field_map_record_roots` 의 cluster list 와 `map1_01a_strict_target_link_gap` 의 direct strict transition rows 0개, source strict cluster row 1개, target strict cluster row 0개, target selector-only cluster rows 5개, current frontier cluster row 를 직접 참조한다. completion audit 도 같은 row count 를 포함해, adjacent strict cluster 가 있어도 `map1_01a -> map2_02d` target link 가 없으면 promotion 하지 않는다는 판정을 유지한다.
- `out/map1_01a_strict_target_link_gap.*` 는 이제 자체 `evidenceRefs=2` 로 `out/field_map_record_roots.json` 와 `out/event_transitions.json` 를 직접 가리킨다. route queue/promotion gate/completion audit/verifier 가 이 fields 를 강제해 P9 strict target-link blocker 도 cluster roots 와 event transition 원본까지 역추적 가능하다.
- P9 strict target-link blocker 도 top-level proof/missing-gate 형식으로 맞췄다. `out/map1_01a_strict_target_link_gap.*` 는 `proofFound=False`, `strictTargetLinkProofFound=False`, `failedStrictTargetLinkGateIds=direct-strict-event-transition,source-outgoing-strict-cluster,target-strict-cluster,selector-only-frontier-not-event-linked`, `missingEvidence=4` 를 직접 싣고, route queue/promotion gate/blocker matrix/completion audit 은 같은 값을 전파한다. 따라서 incoming-only strict cluster 와 selector-only current frontier 가 왜 strict source hotspot/tile hotspot gate 를 풀지 못하는지 한 줄로 추적된다.
- `out/map1_01a_entry_context.json` 은 confirmed route 로 도달한 `map1_01a` entry context 와 `map2_02d` selector-only frontier context 를 분리한다. confirmed `map1_02b -> map1_01a` 는 `0x005032d8` strict event-linked cluster 로 들어오고, `map2_02d` 후보는 별도 `0x00542b44` selector-only cluster 에 있으므로, selector `2:0` 이 confirmed entry path 에서 실행된다는 증거가 나오기 전까지 successor 로 승격하지 않는다.
- `out/map1_01a_selector_bridge_refs.json` 은 confirmed `0:0 / 0x00501808` context 와 frontier `2:0 / 0x00540714` context 를 서로 직접 참조하는 dword bridge 가 있는지 양방향으로 스캔한다. 현재 confirmed-to-frontier, frontier-to-confirmed 모두 0 hits 이며, 이는 완전한 VM 실행 증명은 아니지만 두 context 를 분리하고 `map1_01a -> map2_02d` 를 blocked 로 유지하는 추가 gate 다.
- `out/save_selector_reverse_reuse_context.json` 은 selector merge bridge matrix 의 `2:0 -> 1:0` 역방향 hit 51건을 세부 분류한다. 51건 모두 predecessor fill site `0x004844d0`/`0x004844d8` 이전을 가리키고 fill site hit 는 0개이며, 27건은 dword 정렬도 아닌 payload/text 위치다. 따라서 이 hit 들은 공유 script/resource material 재사용이지 `1:0 -> 2:0` 실행 순서 증명이 아니며 selector merge 는 blocked 유지다.
- 같은 reverse reuse context 도 P2 source report 형식에 맞춰 `proofFound=False`, `reverseReuseProofFound=False`, `failedReverseReuseGateIds=predecessor-current-forward-bridge,reverse-reuse-fill-site-hit,selector-2:0-runtime-or-savedata,strict-source-hotspot`, `missingEvidence=4`, `evidenceRefs=3` 을 직접 싣는다. 따라서 역방향 reuse 51건이 있어도 forward bridge, fill-site hit, real selector `2:0`/selected-root runtime, strict source hotspot 이 없으면 selector merge proof 로 승격하지 않는다는 점을 ref 파일 하나에서 확인할 수 있다.
- P2 next-action refs 는 이제 `out/save_selector_merge_bridge_matrix.json` 과 `out/save_selector_reverse_reuse_context.json` 도 직접 가리킨다. `route_investigation_queue`, `route_promotion_gate`, `completion_audit` verifier 가 같은 direct ref 를 강제하므로, selector merge blocker 를 볼 때 source/current/predecessor bridge hit `0/0/51`, before-fill-only `True`, forward encoded anchor `3/0`, reverse reuse aligned/unaligned `24/27`, fill-site hit `0`, merge proof `blocked` 를 원본 bridge matrix 및 reverse reuse context 에서 바로 확인할 수 있다.
- `out/map1_01a_manifest_point_scan.json`/`.md` 은 `map1_01a` manifest record 3개 주변의 point-table 후보를 다시 스캔한다. `0x00503364 -> 0x0050336c` 24-point table 은 확인되지만 소유자가 `map1_02b@0x00503350` incoming strict event 이므로 `map1_01a` source hotspot 이 아니다. 즉 현재도 `map1_01a -> map2_02d` 를 승격할 strict source coordinate 는 없다.
- `out/map1_01a_root_point_scan.json`/`.md` 은 current selector `2:0` root `0x00540714..0x00543578` 전체의 hidden point-table 후보를 스캔한다. point-like pointer 는 448개지만 `map1_01a -> map2_02d` geometry exit sample 과 정확히 맞는 후보는 0개이고, 상위 후보는 `0x00010021` 같은 VM command word 가 좌표처럼 보이는 script-like false positive 라서 current-root point-table 경로도 promotion 근거가 아니다.
- `out/field_map_record_roots.json` 은 EXE 주소상 가까운 field-map scene record 와 strict event record 를 root 후보로 묶는다. 현재 32개 interesting cluster 중 strict event-linked 11개, selector-only 21개이며, 현재 frontier 는 `0x00542b44..0x00542e74` 의 selector-only cluster 1개로 분리된다. scene record 의 앞쪽 리소스 블록을 적용하면 이 cluster 의 `map1_01a -> map2_02d` source/target tileset 은 accepted render 와 맞지만, strict event record 가 없고 strict source coordinate/hotspot 도 없다. 근처 `0x005032d8..0x00503350` cluster 는 `map1_02b` strict event record 가 `map1_01a` 로 이어지는 구조라, 실제 전환 promote 는 strict event-linked cluster 쪽을 우선 기준으로 삼는다. 이번 pass 부터 이 report 자체도 `proofFound=False`, `fieldMapRecordRootsProofFound=False`, `failedFieldMapRecordRootGateIds=4`, `missingEvidence=4`, `evidenceRefs=5` 를 싣고 P9 route queue/promotion gate refs 가 이 값을 직접 가리킨다. HTML 표면은 cleanup 이후 기본 산출물에서 제외한다.
- `out/transition_review_shortlist.json` 은 `out/field_map_record_roots` 의 root classification 을 함께 표시한다. 각 active-nearest 전환 후보에 `strict event-linked cluster` 여부, root 시작 VA, root 주변 scene record 의 accepted render mismatch 수를 붙인다. 따라서 다음 수동 확인은 같은 좌표 후보라도 selector-only 후보가 아니라 strict event-linked 후보를 우선 열고, render mismatch 가 적은 후보부터 볼 수 있다. `out/transition_review_shortlist_audit.html`/`.json` 은 이 shortlist 가 `manual-review-only`/`not-auto-confirmed` 상태임을 별도 고정한다. `transition_review_shortlist.html` 표면은 cleanup 이후 기본 산출물에서 제외한다. 현재 24개 후보는 모두 strict event-linked/zero-render-mismatch/active-distance 0 이고, confirm-nearest patch preview 24개가 생성 patch 파일과 일치하지만 `data/transition_reviews.json` 에 수동 merge 되기 전까지 normal route 에는 영향이 없다. 같은 `map2_03l:11,11` active point 가 `map2_01c`/`map2_13c` 로 각각 5개 record/root 에 중복되므로, EXE record 단위 수동 판별이 여전히 필요하다.
- hotspot tail 에 연결된 `z*.cns` 오브젝트 리소스를 `out/object_assets.js` 로 자동 등록하고 PNG 디코드/HUD 미리보기 가능. 웹 `events=1` 디버그 오버레이는 연결된 오브젝트 이미지를 active point 위에 후보 preview 로 렌더링하지만, 이는 원본 NPC/object descriptor 실행 증거가 아니라 검토용 overlay 다.
- 같은 맵에 여러 타일셋 묶음이 있으면 웹 상단 중앙 variant 선택으로 즉시 비교 가능.
- `tools/summarize_scene_events.py` 와 `out/scene_events_summary.md` 로 이벤트 후보 맵/좌표/linked object/blockKind 요약 가능.
- `tools/summarize_scene_dispatch_refs.py` 와 `out/scene_dispatch_summary.md` 로 이벤트 dispatch 역참조/조건 블록 후보 요약 가능.
- 모든 `map[0-9]*.cns` 필드 맵 174개를 웹 맵 선택 프로토타입에 추가.
- `web/index.html` 에 최소 Canvas 타이틀 화면, 실제 타일맵 기반 방향키 이동, 캐릭터 추적 카메라, 맵 전환 프로토타입 추가.
- 현재 맵 타일은 `data/map_layout_reviews.json` 에 accepted 로 고정한 planar 2레이어, 40열 선형 타일셋, 0-based 타일 ID 매핑(`0` 빈칸, 그 외 값을 그대로 source tile index 로 사용)을 적용해 렌더링 중이다. 두 번째 plane 의 정확한 draw/occlusion 의미는 아직 원본 draw 루틴으로 추가 확인이 필요하다.
- `layer1` tile ID `1`, `2` 는 상층 filler/마스크처럼 보여 현재 `emptyLayer1Tiles` 로 보존하고, 시각 렌더링과 fallback 통행 판정에서는 빈 상층 타일처럼 처리한다.
- 기본 맵 렌더링은 파일명 접미사 기준 타일셋으로 되돌렸다. `map1_02b` 를 EXE 장면 테이블 후보인 `map_f*` 로 그리면 큰 윤곽은 나오지만 타일 의미가 틀리고, `map_b1/map_b2` 로 그릴 때 동굴/폭포/다리 타일이 맞는다. EXE 장면 테이블의 타일셋 묶음은 `observedSceneTilesets`/`sceneTilesetVariants` 로 보존해 웹에서 비교한다.
- 수동 `transitions` 는 맵 구조 재검증 중 제거. 원본 이벤트/스폰 좌표 식별 후 다시 추가 필요.
- `extract_wlk/00.wav`, `01.wav`, `03.wav`, `04.wav`, `07.wav`, `08.wav`, `09.wav`, `11.wav`, `12.wav` 를 웹 프로토타입의 이동/대사/메뉴/맵 전환/전투 시작/타격/도구/승리 효과음으로 연결.
- 실행파일 CNS 그룹에 같이 묶인 `map5_07h`, `map7_02f`, `map7_03h` 를 웹 맵 선택 프로토타입에 추가.
- 같은 맵이 여러 타일셋 묶음으로 로드되는 11개 케이스는 `sceneTilesetVariants` 로 보존하고, 현재 런타임에서 variant 를 선택해 비교할 수 있다.

## 최근 opcode20 descriptor script 보강

- `out/save_selector_opcode20_descriptor_scripts.html` 의 descriptor+4 `context+0xa8` non-pointer setter-shaped row 16개를 operand source 까지 다시 분류했다. 모두 opcode `0x42` mode `0x00` 이며 handler `0x0040644f` 는 `context[0xf2]` 로 `0x0059db30` object-pointer table 을 읽어 `context+0xa8` 에 쓰는 경로라서, 고정 route/gate base 가 아니라 `context-f2-runtime-object-pointer:16` 이다. 이 값은 `out/route_investigation_queue.*` 의 `nonPointerSource=context-f2-runtime-object-pointer:16`, `out/completion_audit.*` 의 `script4NonPointerContextA8Sources=context-f2-runtime-object-pointer:16`, verifier 로 전파했다. Descriptor+4 field-map/direct/encoded route-target/gate reader-writer 증거는 계속 0이고, opcode `0x20` descriptor path 는 promotion blocked 상태를 유지한다.

- 이번 pass 에서는 같은 `context+0xf2` 소스 증거를 `out/save_selector_gate_base_proof_gap.*` 자체에도 직접 넣었다. Gate-base proof gap 은 이제 `out/save_selector_opcode20_context_f2_sources.json` 의 refs/read/write `204/141/63`, runtime object table readers `65`, initializer/copy/constant writes `2/61/0`, object selectors/fixed-stream2 selectors `16/0`, `specificRuntimeObjectPointerProven=False`, `runtimeObjectTableStateRequired=True`, diagnostic route samples/status `210/diagnostic-only`, promotion `blocked` 를 자체 필드로 보존한다. `out/route_promotion_gate.*` 와 `out/completion_audit.*` 도 `gateBaseProofContextF2=204/141/63/65/2/61/0/16/0/False/True/blocked` 로 같은 값을 노출하므로, opcode `0x20` gate-base blocker 를 볼 때 별도 context-F2 페이지를 열지 않아도 non-pointer `context+0xa8` row 가 runtime object-table state 없이는 fixed route base 가 아니라는 결론을 확인할 수 있다.
- 같은 gate-base proof gap 은 이제 `evidenceRefs=19` 도 직접 갖는다. refs 는 current writer path, opcode20 nested base mode, descriptor scripts, sample order effects, gate pass matrix, patched selector follow-up, public predecessor active-order poll 2종, gate offset source/pattern, gate base candidates/sample values, selection-buffer bases, opcode20 object/order/slot/descriptor-writer/runtime-materializer scans, context-F2 source scan 으로 이어진다. 이 ref count 와 path 목록은 route investigation queue, route promotion gate, blocker matrix, completion audit verifier 에 전파된다.

## 최근 branch gate 보강

- `out/save_selector_branch_gate_consistency.html` 은 nearest writer `0x005428bc` 와 frontier reader `0x00542b0c` 사이의 same-slot 보존 상태를 더 좁혔다. 같은 `secondaryBranchState`/`selectionBuffer[0x20]` 에 대해 writer 이후 frontier reader 전까지 same-offset write/read 는 `0/0` 이고, 다른 selection writer 3개는 `0x0a,0x0d,0x68` offset 만 건드린다. Intervening secondary fill 3개도 helper argument `0x54,0xe6,0xe7` 로 out-of-range 라 유효 fill 이 아니므로 `knownOpcodeStatePreservationStatus=same-selection-slot-preserved-known-opcodes` 로 고정했다. 이 값은 `out/route_investigation_queue.*`, `out/route_blocker_evidence_matrix.*`, `out/completion_audit.*`, verifier 에 전파했다. Slot 보존은 좁혔지만 selected value `1`, control path, strict hotspot, real selector `2:0` save/runtime trace 는 여전히 미증명이라 promotion 은 blocked 다.

## 최근 predecessor fill/branch gate 연계 보강

- `out/save_selector_predecessor_fill_site_execution_context.json` 과 `out/save_selector_predecessor_branch_state_execution_gap.html` 이 branch gate same-slot 보존 증거를 직접 포함한다. Predecessor fill context 는 `branchGatePreserve=same-selection-slot-preserved-known-opcodes`, same offset `True/0x20`, same-offset write/read `0/0`, other writes `3@0x0a,0x0d,0x68`, invalid secondary fill offsets `0x54,0xe6,0xe7` 을 `state-preservation-vs-execution` evidence 로 고정한다. 따라서 predecessor `1:0` 경로의 남은 차단점은 same-slot 보존 자체가 아니라 fill-site 실행/order, public predecessor runtime poll 의 all-zero branch-state, selector merge/order 미증명으로 좁혀졌다. 이 값은 `out/route_investigation_queue.*`, `out/route_promotion_gate.*`, `out/route_blocker_evidence_matrix.*`, `out/completion_audit.*`, verifier 에 전파했고 promotion 은 blocked 상태 그대로다.
- `out/runtime_predecessor_coordinate_source_scan.json` 의 좌표 출처 증거도 같은 p1 chain 에 직접 전파했다. Public start `(5,15)` 는 pointer/static/trail/image `0/1/0/2`, observed trail `(15,26)` 은 `0/0/7/10`, reciprocal target aggregate 는 `0/0/0/118` 로 집계되고 rejection 은 `save-camera-memory-only-no-route-object-coordinate-source` 다. 즉 public predecessor start 와 reciprocal target hint 가 route object/trail source 로 잡히지 않으므로, coordinate source scan 은 fill-site execution/order proof 가 아니라 remaining proof 를 더 좁히는 negative evidence 로 유지된다.

## 최근 selector merge 보강

- `out/save_selector_merge_execution_gap.html` 과 `out/save_selector_merge_runtime_context.json` 의 selector merge blocker 를 다시 확인했다. Current selector `2:0` 은 source `0:0` + predecessor `1:0` shape 처럼 보이지만, source/current bridge `0/0`, predecessor/current bridge `0/51`, `forwardMergeBridgeHitCount=0`, reverse before-fill hit `51`, reverse fill-site hit `0` 이라 forward execution/order 증거가 없다. Address-adjacent alias `10:0` 은 public captured save forward sample 로 덮이지 않고 `address-adjacent-alias-data-only` 로 분류되므로, selector merge 는 `selectorMergeExecutionProofFound=False`, `selectorMergeGapOpen=True`, `promotionStatus=blocked` 로 유지한다. 이 값은 `out/route_promotion_gate.*` 의 `forwardMerge=0` 및 `out/completion_audit.*` 의 `forwardMergeBridgeHitCount=0` evidence 로 전파했고, verifier 도 같은 문구를 요구한다.

## 최근 predecessor fill opcode10 보강

- `out/save_selector_predecessor_fill_opcode10_context.json` 은 predecessor `1:0` fill fragment `0x004844d0..0x004844e0` 의 두 opcode `0x10` row 를 byte 단위로 해석한다. Row value `0x00000210` 은 opcode byte `0x10`, table selector byte `0x02`, helper case byte `0x00` 이며, opcode `0x10` handler `0x0040b49e` 는 table selector 가 nonzero 일 때 secondaryBranchState `0x0059e360` 을 고르고 helper case `0` 이 첫 2칸을 `0x01,0x01` 로 채운 뒤 나머지를 `0x00` 으로 둔다. 따라서 두 fill row 는 branch-state fill 의미 자체는 설명하지만, fill-site text ref `0`, current-reader text ref `0`, root-tail branch/fallthrough-to-fill `0/0/0`, runtime poll fill matches `0`, proof gates `0/6` all-blocked 때문에 여전히 “실행 순서 증명”이 아니라 blocked evidence 다. 이번 pass 에서 opcode10 context 자체에 `failedPredecessorFillOpcode10GateIds=root-entry-to-fill,descriptor-boundary-bridge,dispatch-slice-runtime-proof,runtime-fill-observed,route-order,selector-merge-closed`, `missingEvidence=6`, `evidenceRefs=6` 을 포함시켰고, 이 decoded/proof-gate evidence 는 `out/route_investigation_queue.*`, `out/completion_audit.*`, verifier 에 `decodedFill=secondaryBranchState/2,2/0x01,0x01,0x00...` 및 `requiredProofGateFailIds=root-entry-to-fill,...` 형태로 전파했다.

## 최근 selected-root 보강

- `out/save_selector_selected_root_execution_gap.html` 의 hook prerequisite gate 를 추가로 고정했다. selected-pointer global `0x0059de30` 의 `.text` ref 6개는 trace hook target 이지만, save-loader hook 은 captured selector `2:0`, opcode07 hook 은 indexed slot 이 current root, opcode08 hook 은 이미 selected pointer 가 current root, opcode09 hook 은 current stream/operand 가 current range 여야 한다. 따라서 hook/prerequisite/self-proving/promoting 은 `6/6/0/0`, hook window route-specific hit 는 `6/0`, all-unproven `True`, status `trace-targets-prerequisites-unproven` 이고, `.text` ref 6개 자체는 selected-root execution proof 로 승격하지 않는다. 이번 pass 에서 handler-rooted bounded direct-call graph 도 추가해 handler root/function/direct-call `4/15/27`, route/current/record/selector/branch hit `0/0/0/0/0`, generic selected-pointer/selector-table hit `6/1`, depth sensitivity `4/True/True` 를 고정했다. 이 call graph 는 `selected-pointer-handler-callgraph-generic-only-contrast` 로 blocked 이며, `out/route_investigation_queue.*`, `out/route_promotion_gate.*`, `out/route_blocker_evidence_matrix.*`, `out/completion_audit.*` 와 verifier 에도 전파했다.
- `out/save_selector_route_pair_index_source_gap.html` 은 selector `2:0` route-pair index source 의 직접 포인터 참조 경로를 별도 차단한다. Current route entry index 는 `-13,-12,6,8` 이며 `-13` entry pointer ref 는 0개, `-12`/`6`/`8` entry pointer ref 는 각각 1개뿐이다. 이 3개는 모두 opcode `0x5a` mode0 fallthrough word 이고 low-byte handler 가 `0xac->0x00000003/-`, `0xf4->0x00000004/-`, `0xfc->0x004409b8/.data` 로 executable code 가 아니며, `.text` ref/promoting ref 는 0개다. Descriptor refs 는 leaf-table cell 로만, child refs 는 descriptor child word 로만 나타나므로 직접 포인터 참조만으로는 higher-level index 가 entry `6`/`8` 또는 negative wrapper `-12` 를 선택했다는 증거가 없다. `out/save_selector_route_pair_entry_execution_gap.html` 은 이 결과를 포함해 selector `2:0` current-root route-pair entry `6`/`8` 의 실행 공백을 통합한다. 두 entry 의 corrected trace 는 reader `0x00542b0c` 까지 닿지만 전역 leaf-table 기준 current route-pair index 는 `-13,-12,6,8` 이고 frontier reader-bearing leaf 는 negative `-12` 에만 있다. opcode `0x07` 직접 선택은 0건이고, source/predecessor opcode `0x08` current root/range producer 및 opcode `0x09` current-range store 도 모두 0건이다. 이번 pass 에서 route-pair entry gap 은 opcode `0x08` bucket 을 selector별로 보존해 source/predecessor 는 `0:0 op8=31 currentRootRange=0/0 own=9 script=21 unreadable=1`, `1:0 op8=131 currentRootRange=0/0 own=15 script=86 unreadable=30` 이고 current `2:0` 만 내부 continuation `currentRootRange=0/24` 를 가진다는 contrast 를 `out/route_investigation_queue.*`, `out/route_promotion_gate.*`, `out/route_blocker_evidence_matrix.*`, `out/completion_audit.*` 에 전파한다. opcode `0x09` source/predecessor unsupported mode row 5개는 `0x0047da5c/0x0047dad4/0x0047dbcc/0x0047dc88` 의 `0x6c` `.data` collision 과 `0x0047f2ac` 의 `0xfe` `.text` collision 이며 store 없이 반환되고, wrapper entry ref 도 current-root entry-run 0/opcode5a fallthrough 1/promoting 0이라 corrected trace 는 table shape 증거로만 남는다. current root table refs 는 `rootTableRefs=14/0`, `rootTableEntryLeafFrontierReaderText=0/0/0/0`, `rootTableFrontierReaderRefs=0` 으로 모두 data-only/no-text-ref 문맥이다. 그 wrapper fallthrough word 는 `0x005429ac/0xac->0x00000003/-` 로 분류되어 code-backed wrapper jump 가 아님을 `out/route_blocker_evidence_matrix.*`, `out/route_promotion_gate.*`, `out/completion_audit.*` 에 같이 반영했다. selected-root execution ref, wrapper execution proof, strict hotspot 이 모두 false 라 entry execution proof 는 blocked 로 남는다.
- 같은 route-pair entry gap 은 이제 자체 `evidenceRefs=10` 을 싣는다. refs 는 leaf index space, leaf-table global/local context, opcode `0x07/0x08/0x09` scans, wrapper descriptor context, selected-root execution gap, current-root frontier paths, route-pair index-source gap 을 직접 가리키며, route queue/promotion gate/blocker matrix/completion audit/verifier 가 같은 count/path 를 강제한다.
- P6 next-action refs 는 이제 `out/save_selector_route_pair_index_source_gap.json` 도 직접 가리킨다. `route_investigation_queue`, `route_promotion_gate`, `completion_audit` verifier 가 같은 direct ref 를 강제하므로, selected-root/leaf-selection blocker 를 볼 때 route-pair entry gap 을 거치지 않아도 entry pointer refs `3/0/0`, encoded anchor `3/0/0/0`, fallthrough non-code refs `3/3`, higher-level index source `False` 를 원본 index-source report 에서 바로 확인할 수 있다.
- `out/save_selector_route_pair_index_source_gap.*` 자체도 `evidenceRefs=2` 를 싣는다. refs 는 current selector route rows 를 담은 global leaf-table context 와 opcode handler classification 을 담은 script handler table 을 직접 가리키며, P6 next-action verifier 가 이 fields 를 함께 강제한다.
- 이번 P6 보강에서는 `out/save_selector_selected_root_execution_gap.*` 자체도 top-level `remainingProofs=5` 와 `evidenceRefs=8` 을 노출한다. 남은 증거는 captured selector `2:0` save, `0x0059de30 -> 0x00540714` runtime proof, non-current root/range selected-pointer producer proof, `0x00440720` save-selector slice execution proof, strict `map1_01a` source hotspot 이며, 이 count/ref 는 `out/route_investigation_queue.*`, `out/route_promotion_gate.*`, `out/route_blocker_evidence_matrix.*`, `out/completion_audit.*` 와 verifier 에 전파된다.
- 추가 P6 traceability pass 에서 next-action refs 는 `out/save_selector_leaf_table_global_context.json`, `out/save_selector_route_pair_descriptor_context.json`, `out/save_selector_opcode2c_route_pair_context.json` 도 직접 포함한다. 따라서 queue/gate/audit 만 열어도 current selector route rows `-13,-12,6,8`, frontier reader leaf negative-only, opcode `0x2c` corrected trace 2/2 reader reachability, runtime selection/proof false, failed gate/missing evidence 를 route-pair entry gap 을 경유하지 않고 확인할 수 있다.
- `out/runtime_selected_pointer_synthetic_selector_2_0_input_path_case_alias_poll.json` 은 input-path/case-alias load path 에 standalone synthetic selector `2:0` save-shaped 파일을 staged 해 2개 sequence/374 sample 을 수집했지만 selector `8:0` 만 관측했고 staged selector/current root/route hit 는 0회였다. 이 결과는 `out/save_selector_selected_root_execution_gap.html`, `out/route_blocker_evidence_matrix.html`, `out/route_investigation_queue.html`, `out/completion_audit.html` 에 non-promoting contrast 로 통합되어, patched public-base diagnostic 이 constructed `2:0` load 가능성을 보인 것과 별개로 standalone synthetic 파일은 selected-root execution proof 가 아님을 고정한다.
- `out/runtime_source_exit_poll_context.json` 은 public selector `0:0` source save(`HandyHwanseEditor/bin/Debug/savedat2.dat`) 를 `SaveData/savedat1.dat` 로 staged 한 source-exit runtime poll 을 raw poll 과 load-confirmed poll 로 나눠 요약한다. Raw 4 sequence/7246 sample 은 이제 staged public selector `0:0` 을 관측하고 observed selector 는 `48:13,0:0` 이지만, 네 routeAssist 후보(top `18,0`, bottom `16,47`, left `3,14`, right `34,19`) 모두 candidate/outside tile, actor/trail coordinate, selector `2:0`, current root hit 가 0이다. Load-confirmed prefix `Down,Return,Return` 을 붙인 5 sequence/7923 sample 도 public selector `0:0` 을 관측하지만 observed selector 는 `50:0,48:13,0:0` 이고 같은 네 후보 모두 route/current/candidate/outside hit 가 0이며 branch-state 는 all-zero 다. 따라서 분류는 `source-save-observed-candidate-not-observed` 이고, 이 source save/input-path 조합은 source-load context 일 뿐 strict `map1_01a` source hotspot 또는 selected-root execution proof 로 쓸 수 없다.
- `out/runtime_source_save_load_variant_context.json` 은 같은 source selector `0:0` public save 의 loadability/start-coordinate 와 exit-path 증거를 분리한다. load-only 변형 4 sequence/938 sample 에서는 Debug/Release `0:0` save 가 실제로 관측되고 observed selector 는 `50:0,0:0,48:13` 이다. coordinate-aware load-only 4 sequence/869 sample 에서는 모든 sequence 가 selector `0:0` 과 source camera tile `0,2` 를 함께 관측했고 observed selector 는 `0:0,48:13` 이다. warmup 포함 fixed exit-path 재검증 5 sequence/7923 sample 은 selector `50:0,48:13,0:0` 의 non-route 경로이고, 네 후보(top `18,0`, bottom `16,47`, left `3,14`, right `34,19`) 모두 candidate/outside tile, actor/trail coordinate, selector `2:0`, current root hit 가 0이며 branch-state 는 all-zero 다. 추가 adaptive exit 재검증 4 sequence/1881 sample 은 네 후보 모두 source-ready 로 시작했고 observed selector 는 `0:0,48:13` 이지만 candidate/outside tile, selector `2:0`, current root hit 는 0이었다. trail0 start `10,7` 변형도 4 sequence/1476 sample 에서 네 후보 모두 source-ready 를 잡았고 observed selector 는 `0:0,48:13` 이지만 같은 route/current/candidate-outside hit 는 0이었다. 이제 `readyPathSummary` 는 source-ready path 8개가 모두 첫 non-source selector `48:13`(`map2_04l,map2_05e`) 로 빠지고 route/current/candidate-outside hit 가 `0/0/0` 임을 `source-ready-path-diverts-to-48:13-before-exit-candidates` 로 고정한다. 이번 pass 의 `diversionSelectorContext` 는 그 `48:13` 이 `48:9,48:13` alias group(`map2_04l,map2_05e`) 에 속하고 `map2_04l -> map2_05e` selector-adjacency-only row 1개만 가지며 strict/confirmed edge, source/target map 포함, selected-pointer current proof, route-promotion evidence 가 모두 0임을 `non-route-selector-adjacency-only` 로 고정한다. 따라서 분류는 `source-ready-adaptive-exit-no-route` 이고, 이 source save 는 load/start-coordinate 및 non-promoting source-ready exit attempt context 로만 쓰며 strict exit hotspot 또는 selected-root execution proof 로 승격하지 않는다. 이 리포트도 이제 `proofFound=False`, `runtimeSourceSaveLoadVariantProofFound=False`, `failedRuntimeSourceSaveLoadVariantGateIds=strict-source-hotspot,selected-root-execution,route-selector-current-root-observation,source-exit-candidate-observation,route-promotion-evidence`, `missingEvidence=5`, `evidenceRefs=8` 을 직접 싣고 P5 next-action refs/verifier 가 강제한다. 이 분류와 diversion context 는 `out/route_promotion_gate.*` 의 strict/tile/selected-root/runtime-trace hard gate evidence 와 `out/completion_audit.*` 의 blocker-row gate evidence 로도 전파된다. 따라서 promotion gate/audit 만 봐도 source save 가 로드되고 source-ready path 일부가 실행됐지만 strict hotspot, selector `2:0`, current root, route/current/candidate-outside hit 가 모두 0이라 hard gate 를 열 수 없음을 확인할 수 있다.
- `out/runtime_opcode24_flag_context.json` 은 runtime opcode24 watch 값들을 한데 묶어 `0x0059e34d` runtime flag 가 route proof 로 오해되지 않게 고정한다. `out/runtime_route_watch_values_poll.json` 의 late menu poll 1 sequence/1123 sample 에서 `opcode24RuntimeFlag=0x01` 이 340 sample 관측되지만 selector 는 `8:0,50:0` 뿐이고 `opcode24Mode1Source=0x00`, `opcode24CurrentObjectIndex=0x00`, selector `2:0`/current root hit 는 0이다. source-save fixed exit load-confirmed 7923 sample, source-save adaptive 1881+1476 sample, predecessor sweep/activation 3380+2299 sample, constructed selector `2:0` diagnostic 375 sample 모두 mode1 source/current object 는 계속 `0x00` 이다. 따라서 분류는 `runtime-flag-nonroute-mode1-zero` 이고, 다음 유효한 proof target 은 여전히 `0x0059e348` mode1 source 의 real runtime producer 또는 strict `map1_01a` hotspot 이다.
- 같은 opcode24 flag context 는 이제 `out/runtime_source_save_load_variant_context.json` 의 source-save diversion 요약도 직접 담는다. Source-save classification 은 `source-ready-adaptive-exit-no-route`, ready path diversion 은 `source-ready-path-diverts-to-48:13-before-exit-candidates`, ready paths 는 `8/0/0`, diversion selector 는 `48:13`/`map2_04l,map2_05e`, selected-pointer current proof count 는 0, route promotion evidence 는 false 다. 이제 이 context 도 `proofFound=False`, `runtimeOpcode24FlagProofFound=False`, `failedRuntimeOpcode24FlagGateIds=mode1-source-runtime-producer,runtime-flag-route-context,selected-root-execution-proof,source-save-route-promotion-evidence,strict-hotspot-or-equivalent-runtime-trigger`, `missingEvidence=5`, `evidenceRefs=7` 을 top-level 로 싣고 P8 next-action refs/verifier 가 강제한다. 2026-06-09 추가 pass 에서는 P8 refs 에 `realRouteHitObserved=False`, `constructedRouteHitObserved=True`, `runtimeFlagNonzeroObserved=True`, `currentObjectIndexNonzeroObserved=False`, `routePromotionEvidenceFound=False`, `sourceSaveLoadPromotionStatus=blocked`, `sourceSaveLoadDiversionFieldMaps=map2_04l,map2_05e`, `sourceSaveLoadDiversionRoutePromotionEvidenceFound=False` 도 직접 넣었다. 그래서 P8 action 의 `runtimeOpcode24FlagContext` evidence 만 봐도 `runtimeFlag=1` menu observation, constructed diagnostic exclusion, source-save/adaptive/predecessor all-zero watch, source-save non-route diversion 이 하나의 blocked 결론으로 연결된다.
- `out/runtime_selected_pointer_predecessor_left_overrun_activation_sweep_poll.json` 은 public predecessor `1:0` save 를 input-path/case-alias 조건으로 staged 하고 left-edge overrun 뒤 `Return`/`z`/`space` activation tail 을 붙인 4개 sequence/2299 sample 을 폴링했다. observed selector 는 `50:0,19:1,1:0`, observed public selector 는 `1:0` 이지만 `2:0`/current root hit 는 0회이고 opcode24 watch byte 는 모두 `0x00` 이다. 이 결과는 `out/save_selector_selected_root_execution_gap.html`, `out/route_investigation_queue.html`, `out/route_promotion_gate.html`, `out/completion_audit.html` 에 non-promoting selected-root evidence 로 통합되어 left-edge activation 변형도 route proof 가 아님을 고정한다.
- `out/runtime_predecessor_route_attempt_context.json` 은 기존 predecessor `1:0` runtime poll 13개를 한 evidence contract 로 압축한다. 총 60 sequence/59,816 sample 에서 public predecessor selector 를 관측한 파일은 11개지만 selector `2:0` hit 와 current root `0x00540714` hit 는 모두 0회다. 관측 selector 분포는 `19:1` 30,975 sample, `50:0` 22,685 sample, `1:0` 5,587 sample, `8:0` 569 sample 이며, left-overrun/nearest/reciprocal/trail 변형 모두 predecessor-to-current runtime transition proof 로 승격하지 않는다. 이번 pass 는 그 selector 분포를 정적 문맥까지 확장해 `19:1` 을 `map3_02f..map3_07h` 의 non-route field-map selector-only adjacency, `8:0` 을 `map5_*` 계열의 non-route field-map selector-only adjacency, `50:0` 을 field map 이 없는 `zh_rai.cns` resource-only selector 로 분류하고 세 selector 모두 current-root producer/strict/confirmed edge/route promotion evidence 0건임을 고정한다. Public predecessor `1:0` 자체도 target-side map set 에 속하지만 current proof count 0, route promotion evidence false 로 남는다. 이 report 자체도 runtime poll glob, mapset alias, scene adjacency, global selected-pointer paths, selector table, selector resource refs 6개를 `evidenceRefs/evidenceRefCount` 로 싣는다. 따라서 이 산출물은 selected-root blocker 의 predecessor-save 가설을 non-promoting 으로 닫고, strict source hotspot 또는 실제 selector `2:0` runtime/save 증거 요구를 유지한다.
- 2026-06-09 route promotion gate/route investigation queue/completion audit 는 이제 `out/runtime_predecessor_route_attempt_context.json` 을 직접 evidence ref 로 싣는다. P1 predecessor fill-site action 과 gate non-promoting row 는 `predecessorRouteAttempt=13/60/59816`, public files `11`, route/current hits `0/0`, dominant diversion `19:1`, diversion contexts `3/2/1`, route evidence `False`, status `blocked` 를 검사한다. 이 연결은 predecessor 런타임 시도 13개가 모두 selector `2:0`/current root proof 로 승격하지 않았음을 상위 산출물에서 바로 보이게 하는 정리이며, normal route promotion 은 여전히 strict source hotspot, real selector `2:0` savedata, selected-root/runtime proof 없이는 열리지 않는다.

## 최근 hotspot 보강

- `out/map1_01a_strict_event_tile_signature_scan.html` 은 전체 strict event 11 record/228 point 의 타일 signature 를 현재 `map1_01a -> map2_02d` 네 후보와 비교했다. 우측 `34,19` 후보만 center-pair match 11건이 있지만 모두 incoming `map1_02b -> map1_01a` rejected review record 소유이고 same-source/target-linked/confirmed center match 는 0건, rejected center match 는 11건(`allCenterPairMatchesRejectedReview=True`), low3x3/pair3x3 match 는 0건이며, `map2_02d` target-linked strict event 와 direct `map1_01a -> map2_02d` strict event 도 모두 0건이다. 이번 pass 에서는 reciprocal target-spawn tile signature 도 같은 strict-event 집합과 비교해 target map strict event point 0개, target-spawn center/pair3x3 match 0개, target-spawn low3x3 match 147개, target-spawn target-map center/low3x3/pair3x3 match 0개(`allTargetSpawnCenterPairMatchesZero=True`, `allTargetSpawnPair3x3MatchesZero=True`, `allTargetSpawnTargetMapStrictEventsZero=True`)로 고정했다. 이 147개 low3x3 overlap 은 owner split 상 `map2_03l->map2_01c,map2_13c:45`, `map1_02b->map1_01a:20`, `map9_01e->map2_04l,map2_05e,map2_06e,map2_08e,map6_01e:20` 등이 상위이고 `map2_02d` target-linked 는 0, confirmed/rejected review 는 `1/19`, generic-only 는 `True` 다. 따라서 target spawn 쪽도 generic low3x3 overlap 이상으로 승격하지 않으며, 이 결과는 `out/route_investigation_queue.html`, `out/route_promotion_gate.html`, `out/route_blocker_evidence_matrix.html`, `out/completion_audit.html` 에 들어가 tile signature 를 diagnostic-only evidence 로 유지하고 tile hotspot confirmation 을 계속 blocked 로 둔다.
- `out/map1_01a_edge_trigger_gap.json` 은 actor-controller/collision-helper 에서 출발하는 bounded direct-call graph 도 추가로 검사한다. 현재 depth 3 기준 reachable function 7개/direct call edge 24개를 훑었지만 map loader/script runner/selector table reachable target 0개, transition hit 0개, selected-pointer/current-root/source/target route immediate 0개이며 indirect-call-like byte 6개만 runtime-proof 필요 후보로 남는다. depth sensitivity 도 1..6 으로 확장해 재실행했고 depth 1 은 function/edge `5/22`, depth 2..6 은 `7/24` 로 안정화되며 모든 depth 에서 transition target/route immediate/indirect route hit 0개, proof `False` 로 유지된다. 이 값은 `bounded-direct-callgraph-no-transition-path`, `proofAbsentAcrossCheckedDepths=True`, `countsStableAtAndBeyondDefaultDepth=True` 로 strict source hotspot context, route investigation queue, route promotion gate, blocker evidence matrix, completion audit 에 전파되고 generic edge trigger 는 계속 `blocked-generic-edge-trigger-unproven` 이다.
- 2026-06-09 edge-trigger indirect jump-table audit 보강: 위 indirect-call-like byte 6개는 모두 indexed jump table 로 풀리며, `out/map1_01a_edge_trigger_gap.*` 의 `Indirect Jump Table Audit` 이 테이블별 target class 를 고정한다. actor-controller 쪽 `0x00430333/0x00430b00/0x00430d61/0x00430fd1` 은 entry `4/4/34/4` 개가 모두 `actor-controller-local`, collision-helper 쪽 `0x00431c96/0x00431f9b` 은 entry `4/8` 개가 모두 `collision-helper-local` 이다. 총 58개 target 중 outside-edge-handler 0, transition table labels 0, route table labels 0 이므로 indirect jump table 도 map loader/script runner/selector table/current root/source-target string proof 로 승격하지 않는다.
- 같은 edge-trigger graph 의 indirect 후보 6개도 opcode/ModRM/SIB 기준으로 다시 풀었다. 모두 `ff 24 85 ...` indexed jump table 이며 6개 table/58개 `.text` entry 를 제한 스캔했지만 map loader/script runner/selector table target hit 0개, selected-pointer/current-root/source/target route hit 0개라 `bounded-indirect-callgraph-no-static-transition-target` 으로 고정한다. 이 분류도 strict source hotspot context, route promotion gate, blocker evidence matrix, completion audit 에 전파되어 generic edge-trigger 의 indirect-table 변형 역시 normal transition proof 가 아니다.
- 같은 edge-trigger pass 는 route-target scalar 가 직접 dword 로 박혀 있지 않은 경우를 배제하기 위해 `abs16-low`, `signed-rel16-site-plus2`, `signed-rel32-site-plus4` encoded scan 을 추가했다. edge handler/local-window/callgraph 는 raw/transition/routeProof/selectedPointer/promoting 모두 `0/0/0/0/0` 이고, global contrast 만 `4/4/0/0/0` script-runner rel32 hit 로 남아 `edge-encoded-route-target-scalars-nonpromoting` 이다. 이 값은 strict source hotspot context 와 route gate/audit 에 `edgeEncoded=0/0/0/0/0;0/0/0/0/0;0/0/0/0/0;4/4/0/0/0` 로 전파된다.

## 최근 audit traceability 보강

- 2026-06-09 P1 dispatch table-base audit 보강: `out/save_selector_predecessor_fill_execution_order_gap.*` 는 이제 `Dispatch Table-Base Audit` 섹션과 `predecessorDispatchTableBaseAuditRows=6` 을 싣는다. Predecessor root/fill descriptor row `0x004783e0/0x004844dc` 는 save-selector slice 에서는 `.data` descriptor `0x00440a9c/0x00440c5c` 로 해석되고 raw generic table 에서는 `.text` handler `0x0040f02a/0x0040ec00` 로 달라지며, 둘 다 generic byte dispatch 로는 reachable 하지 않고 table-base switch 를 요구한다. 동적 indexed dispatch 3개 `0x00438456/0x004390b7/0x004390f3` 은 모두 SEH scope-table callback(`seh-scope-callback-not-save-selector`) 이고 save-selector table immediate/base 후보 0개, table-base arithmetic scan 도 `116/0` candidate 로 닫힌다. `out/save_selector_predecessor_fill_site_execution_context.*` 는 이 audit row count 를 전파하고, P1 route queue/promotion gate evidence ref 도 `predecessorDispatchTableBaseAuditRows` 를 직접 가리킨다.
- `out/route_investigation_queue.*` 와 `out/route_promotion_gate.*` 의 next actions 는 이제 각 priority 가 어떤 hard failed gate 를 겨냥하는지 `relatedFailedGateIds` 로 직접 보존한다. P1/P6/P7 은 selected-root execution 및 runtime trace/equivalent proof, P4 는 real selector `2:0` savedata 및 selected-root execution, P5/P9 는 strict source hotspot 및 tile hotspot confirmation, P8 은 runtime trace/equivalent 및 selected-root execution 으로 연결된다.
- `out/completion_audit.*` 도 같은 `relatedFailedGateIds` 와 missing-evidence 설명을 blocker row 의 `routePromotionNextActionEvidenceRefs` 에 복사하고, normal progression evidence 문자열에 `gates=...` 를 포함한다. 따라서 completion audit 한 파일만 열어도 open/blocked next action 이 어떤 실패 게이트를 해소해야 하는지 refs/task/why/gate 단위로 역추적할 수 있다.
- `out/completion_audit.*` 는 이제 route next action 을 top-level 로도 노출한다. 현재 `routeNextActionCount=9`, `openNextActionCount=7`, `blockedNextActionCount=2` 이며, open 은 P1/P2/P4/P5/P6/P7/P8, blocked 는 P3/P9 로 분리된다. 따라서 `/goal` 재개 시 blocker row 를 펼치지 않아도 바로 다음 실행 항목과 막힌 항목을 completion audit 에서 확인할 수 있다.
- P1 predecessor fill execution/order blocker 자체도 top-level proof/missing-gate 형식으로 맞췄다. `out/save_selector_predecessor_fill_execution_order_gap.*` 는 이제 `proofFound=False`, `failedPredecessorFillOrderGateIds=localFillStreamReachesCurrentReader,rootEntryFixedTraversalReachesFillSites,fillFragmentEntryCandidateFound,encodedFillEntryControlFlowCandidateFound,rootTailBranchClosureReachesFillOrReader,descriptorSliceRuntimeDispatchProven,rawGenericRouteProofFound,runtimeObservedPredecessorFill,predecessorToCurrentForwardBridgeFound,routeOrderAndSelectorMergeClosed`, `missingEvidence=10` 을 직접 싣고, branch-state gap, route queue, promotion gate, blocker matrix, completion audit 이 같은 값을 전파한다. 따라서 local fill stream, root-entry traversal, encoded entry, root-tail closure, dispatch slice runtime proof, raw generic contrast, runtime fill observation, predecessor-current bridge, route-order/merge closure 중 어느 증거가 빠졌는지 한 줄로 확인할 수 있다.
- P1 data-descriptor opcode source 도 같은 proof/missing-gate 형식으로 맞췄다. `out/save_selector_data_descriptor_opcode_map.*` 는 이제 `proofFound=False`, `failedDataDescriptorGateIds=runtime-leaf-selection,reader-control-path-after-descriptor,predecessor-root-to-fill-control-path,predecessor-fill-descriptor-bridge,strict-source-hotspot`, `missingEvidence=5`, `evidenceRefs=4` 를 직접 싣는다. 따라서 `0x005428f4`, `0x00542a08`, `0x004783e0`, `0x004844dc` 의 low-byte descriptor boundary 가 route/wrapper/predecessor proof 로 승격되지 못하는 이유를 P1 fill-order report 를 거치지 않고 source report 자체에서 확인할 수 있다.
- P1 fill-site/order blocker 의 source chain 도 같은 방식으로 보강했다. `out/save_selector_predecessor_fill_site_execution_context.*` 는 이제 fill execution/order gap, branch-state execution gap, descriptor bridge gap, coordinate source scan, field-entry sequence scan, branch-gate consistency 6개 원본 리포트를 `evidenceRefs=6` 으로 직접 싣고, `out/route_promotion_gate.*` 및 `out/completion_audit.*` 도 이 ref count 를 노출한다. 또한 top-level `proofFound=False`, `failedPredecessorFillGateIds=root-entry-to-fill,descriptor-boundary-bridge,dispatch-slice-runtime-proof,runtime-fill-observed,route-order,selector-merge-closed`, `missingEvidence=6` 을 직접 전파해 P1 next-action refs/verifier 와 promotion/audit normal evidence 가 같은 실패 gate 를 가리키게 했다. 따라서 fill-site context 한 파일에서 0/6 proof gate 실패뿐 아니라 각 실패 근거가 어느 원본 산출물에서 왔는지도 바로 역추적할 수 있다.
- P1 predecessor branch-state execution gap 도 같은 top-level 형식으로 맞췄다. `out/save_selector_predecessor_branch_state_execution_gap.*` 는 이제 `proofFound=False`, `failedBranchStateExecutionGateIds=fill-execution-order-proof,fill-site-execution-context,normal-route-order,vm-bytecode-reset-scope-ruled-out,runtime-branch-state-fill-observed,selector-merge-closed,strict-source-hotspot`, `missingEvidence=7`, `evidenceRefs=7` 을 직접 싣고, route queue, promotion gate, completion audit 이 같은 값을 전파한다. 따라서 predecessor `1:0` fill math 가 맞더라도 fill-site execution/order, fill-site context, normal route order, VM bytecode/reset path, runtime fill observation, selector merge closure, strict source hotspot 이 모두 남아 있어 branch-state execution proof 가 아직 막혀 있음을 한 줄에서 확인할 수 있다.
- P4 real selector `2:0` savedata blocker 도 top-level proof 상태를 명시하도록 정리했다. `out/save_selector_real_savedata_evidence_gap.*` 는 이제 `proofFound=False`, `failedSavedataGateIds=current-selector-2:0,selected-pointer-0x00540714,route-pair-map1_01a-map2_02d,selector-route-evidence,strict-hotspot-or-runtime-trigger`, `missingEvidence=5` 를 직접 싣는다. `out/route_investigation_queue.*`, `out/route_promotion_gate.*`, `out/completion_audit.*` 도 같은 proof/missing-gate 값을 normal evidence 와 P4 next-action refs 에 노출하므로, 내부 checklist 를 펼치지 않아도 real savedata gate 가 왜 막혔는지 바로 확인할 수 있다.
- P5 strict source/hotspot blocker 도 top-level proof/missing-gate 값을 갖도록 맞췄다. `out/map1_01a_strict_source_hotspot_context.*` 는 이제 `proofFound=False`, `failedStrictHotspotGateIds=strict-source-coordinate,tile-hotspot-confirmation,strict-target-link,equivalent-runtime-trigger-proof`, `missingEvidence=4` 를 직접 싣고, route queue/gate/audit 도 같은 값을 전파한다. 이로써 strict source coordinate 와 tile hotspot confirmation 실패가 route gate 의 `strictSourceHotspot`/`tileHotspotConfirmation` failed gate 에 어떻게 연결되는지 한 줄로 추적할 수 있다.
- P5 strict source/hotspot 원본 ref 네 개도 같은 proof/missing-gate 형식으로 맞췄다. `out/map1_01a_strict_hotspot_review_matrix.*` 는 `failedStrictHotspotReviewGateIds=strict-source-coordinate,tile-hotspot-confirmation,selected-root-execution-ref`, `out/map1_01a_exit_coordinate_variant_scan.*` 은 `failedExitCoordinateVariantGateIds=strict-source-coordinate,target-spawn-strict-coordinate,promotable-coordinate-owner`, `out/map1_01a_strict_event_tile_signature_scan.*` 은 `failedStrictEventTileSignatureGateIds=target-linked-strict-event-signature,direct-source-target-strict-event,tile-hotspot-confirmation`, `out/map1_01a_edge_trigger_gap.*` 은 `failedEdgeTriggerGateIds=edge-to-transition-control-flow,runtime-edge-selected-root-proof,strict-source-hotspot` 를 직접 싣는다. route queue/gate/completion audit/verifier 와 P5 next-action refs 가 proof/missing/ref-count 필드를 강제하므로 P5 blocker 는 좌표 변형, tile signature, strict review ledger, generic edge-trigger 중 어느 원본 증거가 빠졌는지 ref 파일에서 바로 추적된다.
- 같은 P5 원본 ref 체인도 표준화했다. `out/map1_01a_strict_hotspot_review_matrix.*` 는 refs 6개, `out/map1_01a_exit_coordinate_variant_scan.*` 과 `out/map1_01a_edge_trigger_gap.*` 은 refs 3개, `out/map1_01a_strict_event_tile_signature_scan.*` 은 refs 4개를 `evidenceRefs/evidenceRefCount` 로 직접 싣고 verifier 가 direct count/path 를 강제한다. 따라서 strict review, coordinate variant, tile signature, generic edge-trigger blocker 가 각각 어떤 원본 JSON/EXE/maps 입력에서 나온 결론인지 한 단계 안에서 추적할 수 있다.
- Selected-root execution blocker 도 같은 top-level proof/missing-gate 형식으로 보강했다. `out/save_selector_selected_root_execution_gap.*` 는 `proofFound=False`, 8개 `failedSelectedRootGateIds`, `missingEvidence=5` 를 직접 싣고, P1/P6 next-action refs/verifier 와 route queue/gate/audit normal evidence 가 `selectedRootTopProof=False`, failed gate list, missing evidence count 를 노출한다. 따라서 selected-root gate 는 이제 subgate 표를 보지 않아도 real selector save, selected-pointer runtime proof, non-current root producer, save-selector slice execution, strict hotspot 이 각각 아직 필요한 상태임을 바로 확인할 수 있다.
- Selected-root 보조 근거인 route root-ref context 도 top-level proof/missing-gate 형식으로 맞췄다. `out/save_selector_route_root_ref_context.*` 는 route selector `0:0/1:0/2:0` root chain 이 table-only 임을 보존하면서 `proofFound=False`, `routeRootRefProofFound=False`, `failedRouteRootRefGateIds=selector-root-code-ref,predecessor-current-root-link,route-order-execution-proof,strict-hotspot-or-real-selector-proof`, `missingEvidence=4` 를 직접 싣는다. route queue/gate/blocker matrix/completion audit 은 이 값을 전파해 `.text` ref 부재, predecessor->current root link 부재, route-order proof 부재가 selected-root hard gate 를 왜 열지 못하는지 한 줄로 확인할 수 있다.
- Current-root frontier path 도 top-level proof/missing-gate 형식으로 맞췄다. `out/save_selector_current_root_frontier_paths.*` 는 selector `2:0` root 의 세 frontier leaf 와 reader leaf `0x00542ae8` 이 source/target scene-list adjacency 를 갖지만 `proofFound=False`, `currentRootFrontierProofFound=False`, `failedCurrentRootFrontierGateIds=normal-current-root-execution,strict-source-hotspot,frontier-event-cluster,reader-branch-target-linkage`, `missingEvidence=4` 로 남긴다. route queue/blocker matrix/completion audit 은 이 값을 전파해 leaf adjacency 가 있어도 정상 current-root 실행, strict source hotspot, non-selector-only event cluster, reader branch target proof 없이는 selected-root/strict hotspot hard gate 를 열 수 없음을 한 줄로 확인할 수 있다.
- Current-root frontier path 리포트는 refs 5개(selector references, leaf streams, stream traces, hotspot gap, field-map record roots)를 직접 싣고, route queue 축약본도 같은 `evidenceRefs`/`evidenceRefCount` 를 보존한다. verifier 는 direct JSON 과 queue row 양쪽에서 ref path 를 검사한다.
- Current-root writer path 도 row-level proof/missing-gate 형식으로 맞췄다. `out/save_selector_current_writer_paths.json` 은 selector `2:0` 내부 writer 4개와 selected-pointer store `0x0054248c`/activator `0x0054246c` 를 유지하면서 각 row 에 `proofFound=False`, `currentWriterPathProofFound=False`, `failedCurrentWriterPathGateIds=source-predecessor-current-producer,non-current-selected-pointer-store,runtime-branch-state-slot-proof,selected-root-execution`, `missingEvidence=4` 를 싣는다. selected-root execution gap, route queue/gate P6 next-action refs, blocker matrix, completion audit 은 이 값을 전파해 current 내부 writer 존재가 외부 source/predecessor producer 나 normal selected-root execution proof 가 아님을 바로 추적한다.
- Runtime trace/equivalent blocker 도 top-level proof/missing-gate 형식으로 맞췄다. `out/runtime_trace_feasibility.*` 는 `proofFound=False`, `failedRuntimeTraceGateIds=runtime-trace-capture-unavailable,stable-watchpoint-session-unavailable,equivalent-selected-root-proof-missing`, `missingEvidence=3`, `evidenceRefs=21` 를 직접 싣고, route queue/gate/audit 이 같은 값을 전파한다. `out/runtime_trace_execution_probe.*` 도 `proofFound=False`, `failedRuntimeTraceExecutionGateIds=3`, `missingEvidence=3`, `evidenceRefs=3` 를 직접 싣는다. 따라서 런타임 트레이스가 현재 VM 에서 캡처 불가이며, 안정적인 watchpoint 세션 또는 equivalent selected-root proof 가 아직 필요하다는 점을 gate/audit 한 줄에서 확인할 수 있다.
- 같은 runtime trace/equivalent blocker 는 이제 자체 `evidenceRefs=21` 도 싣는다. refs 는 runtime trace execution probe, memory snapshot, input/key-sequence probes, selected-pointer poll 계열, route watch-value poll, SaveData load poll 계열, file-I/O trace/strace probes 를 직접 가리키며, route queue/gate/completion audit/verifier 가 runtime trace feasibility count/path 를 보존한다.
- P6 wrapper/current leaf execution blocker 도 같은 top-level proof/missing-gate 형식으로 보강했다. `out/save_selector_wrapper_execution_gap.*` 는 `proofFound=False`, `failedWrapperGateIds=selected-root-execution,current-leaf-selection,wrapper-execution,current-selector-leaf-execution,strict-hotspot`, `missingEvidence=5` 를 직접 싣고, route queue/gate/blocker matrix/completion audit 이 같은 값을 전파한다. 따라서 wrapper gap 한 파일에서 selected-root 실행, current leaf 선택, wrapper 실행, current selector leaf 실행, strict hotspot 중 어떤 proof 가 아직 빠졌는지 바로 확인할 수 있다.
- P6 route-pair entry/index-source blocker 도 top-level proof/missing-gate 형식으로 보강했다. `out/save_selector_route_pair_index_source_gap.*` 는 `proofFound=False`, `failedRoutePairIndexSourceGateIds=direct-entry-pointer-source,encoded-entry-anchor-control-flow,nonnegative-entry-index-source,negative-wrapper-index-source`, `missingEvidence=4` 를 싣고, `out/save_selector_route_pair_entry_execution_gap.*` 는 `proofFound=False`, `failedRoutePairEntryGateIds=selected-root-execution,route-pair-index-source,source-predecessor-current-producer,wrapper-entry-execution,strict-hotspot`, `missingEvidence=5` 를 싣는다. P2/P6 route queue/gate/blocker matrix/completion audit 은 이 값을 전파하므로 corrected trace 가 reader 에 닿아도 normal entry selection, current-root producer, wrapper execution, selected-root execution, strict hotspot 이 없으면 proof 가 열리지 않는다는 점을 한 줄로 확인할 수 있다.
- P6 leaf table/index blocker 도 top-level proof/missing-gate 형식으로 보강했다. `out/save_selector_leaf_table_context.*` 는 `proofFound=False`, `failedLeafTableGateIds=runtime-selector-index,wrapper-frontier-execution,strict-hotspot`, `missingEvidence=3` 를 싣고, `out/save_selector_leaf_index_space.*` 는 `proofFound=False`, `failedLeafIndexGateIds=normal-runtime-selector-root-execution,reader-branch-target-linkage,strict-hotspot`, `missingEvidence=3` 를 싣는다. route queue/gate/completion audit 은 이 값을 보존해 current table shape 와 opcode `0x2c` corrected reader trace 가 있어도 runtime selector/index, reader branch target linkage, strict hotspot 이 아직 proof 로 남는다는 점을 바로 보여준다.
- P7 opcode `0x20` gate-base blocker 도 top-level proof/missing-gate 형식으로 보강했다. `out/save_selector_gate_base_proof_gap.*` 는 `proofFound=False`, `gateBaseProofFound=False`, `failedGateBaseGateIds=opcode20-runtime-base-path,predecessor-state-persistence,strict-source-hotspot`, `missingEvidence=3` 를 직접 싣고, route queue/gate/blocker matrix/completion audit 이 같은 값을 전파한다. 또한 `activeOrderProofFound=False` 와 `gateTimeBaseProofFound=False` 를 분리해 active order 관측만으로 gate-time `context+0xa8` base 를 증명하지 못한다는 점을 한 줄에서 확인할 수 있다.
- P8 opcode `0x24` mode1 runtime producer blocker 도 같은 top-level proof/missing-gate 형식으로 맞췄다. `out/save_selector_opcode24_mode1_runtime_context.*` 는 이제 `proofFound=False`, `opcode24RuntimeProducerProofFound=False`, `failedOpcode24RuntimeProducerGateIds=indirect-runtime-producer,opcode24-route-stream-selection,strict-hotspot`, `missingEvidence=3` 을 직접 싣고, route queue/gate/blocker matrix/completion audit 및 external proof packet/handoff 가 같은 값을 전파한다. 따라서 `0x0059e348` 이 zero-filled non-save runtime byte 이고 diagnostic run 에서도 `0x00` 으로 남는다는 사실과 별개로, 정상 경로 indirect producer, opcode `0x24` route-stream selection, strict hotspot 이 아직 필요한 proof 임을 한 줄로 확인할 수 있다.
- 같은 P8 묶음에서 runtime-enabled flag context 도 top-level proof/missing-gate 형식으로 맞췄다. `out/save_selector_opcode24_runtime_enabled_context.*` 는 `proofFound=False`, `opcode24RuntimeEnabledProofFound=False`, `opcode24ModeDispatchProofFound=False`, `failedOpcode24RuntimeEnabledGateIds=runtime-enabled-flag-producer,mode1-source-runtime-producer,selected-root-or-strict-hotspot-proof`, `missingEvidence=3` 을 직접 싣고, route queue/gate/blocker matrix/completion audit 이 같은 값을 전파한다. 따라서 `0x0059e34d` 가 zero-filled runtime flag 이고 diagnostic row 에서도 `0x00` 이라는 점은 mode dispatch proof 가 아니라, flag producer/mode1 source producer/selected-root 또는 strict hotspot proof 가 남았다는 blocker 로 고정된다.
- Runtime-enabled flag context 도 refs 4개(`Hwanse2.exe`, save loader trace, opcode24 globals, patched selector diagnostic poll)를 갖는다. route queue priority 8 action 은 `evidenceRefs`/`evidenceRefCount` 를 필수 필드로 참조하며, verifier 는 direct JSON 과 queue row 에서 같은 ref path 를 확인한다.
- P2 selector merge closure blocker 도 top-level proof/missing-gate 형식으로 보강했다. `out/save_selector_merge_closure_context.*` 는 `proofFound=False`, `failedSelectorMergeGateIds=selector-merge-execution-proof,selected-root-runtime-execution,predecessor-fill-route-order-proof,strict-source-hotspot`, `missingEvidence=4` 를 직접 싣고, route queue/gate/completion audit 이 같은 값을 전파한다. 따라서 selector `2:0` 이 source/predecessor selector list 의 shape 합성처럼 보이지만 forward execution bridge, selected-root runtime execution, predecessor fill/route-order proof, strict source hotspot 이 모두 아직 필요하다는 점을 closure context 한 줄에서 확인할 수 있다.
- 같은 P2 묶음에서 `out/save_selector_merge_execution_gap.*` 와 `out/save_selector_merge_runtime_context.*` 도 top-level proof/missing-gate 형식으로 맞췄다. Execution gap 은 `proofFound=False`, `failedSelectorMergeExecutionGateIds=source-current-bridge,predecessor-current-forward-bridge,execution-like-bridge-or-root-ref,branch-state-execution-proof,strict-source-hotspot`, `missingEvidence=5` 를 싣고, runtime context 는 `proofFound=False`, `failedSelectorMergeRuntimeGateIds=selector-merge-execution-proof,selected-root-runtime-execution,predecessor-fill-runtime-proof,route-pair-entry-execution,strict-source-hotspot`, `missingEvidence=5` 를 싣는다. route queue/gate/completion audit 은 이 값을 같이 전파하므로 selector merge blocker 를 execution bridge, runtime selected-root, predecessor fill, route-pair entry, strict hotspot 관점으로 분리해 추적할 수 있다.
- 같은 selector merge 체인에 evidence ref 도 고정했다. `out/save_selector_merge_execution_gap.*` 는 입력 ref 7개, `out/save_selector_merge_runtime_context.*` 는 runtime-gate ref 5개, `out/save_selector_merge_closure_context.*` 는 closure ref 10개를 `evidenceRefs/evidenceRefCount` 로 직접 싣고, route queue/gate/completion audit 및 verifier 가 이 경로를 보존한다. 따라서 P2 merge blocker 와 P1 fill-order blocker 가 같은 selector-merge 증거 체인을 참조할 때 어느 원본 JSON이 gate 를 막는지 ref count 와 path 로 추적할 수 있다.
- P2 selector merge 의 원본 ref 세 개도 같은 proof/missing-gate 형식으로 맞췄다. `out/save_selector_set_decomposition.*` 는 `proofFound=False`, `failedSelectorSetDecompositionGateIds=source-current-control-flow,predecessor-state-persistence,real-selector-2:0-or-selected-root-runtime,strict-source-hotspot`, `missingEvidence=4` 를 싣고, `out/save_selector_target_alias_bridges.*` 는 `failedTargetAliasBridgeGateIds=target-alias-execution-order,branch-state-persistence,real-selector-2:0-or-selected-root-runtime,strict-source-hotspot`, `missingEvidence=4` 를 싣는다. `out/save_selector_merge_bridge_matrix.*` 도 `failedMergeBridgeGateIds=selector-2:0-runtime-or-savedata,source-current-vm-control-flow,strict-source-hotspot`, `missingEvidence=3` 을 직접 노출하므로 P2 next action 이 set-shape, address-adjacent alias data link, direct/encoded bridge matrix 각각에서 왜 selected-root execution proof 로 승격되지 않는지 ref 파일만으로 확인할 수 있다.
- 같은 P2 source-chain ref 도 표준화했다. `out/save_selector_set_decomposition.*` 는 refs 5개, `out/save_selector_target_alias_bridges.*` 는 refs 5개, `out/save_selector_merge_bridge_matrix.*` 와 `out/save_selector_route_root_ref_context.*` 는 refs 2개를 `evidenceRefs/evidenceRefCount` 로 직접 싣고, route queue/promotion gate/completion audit/verifier 가 P2 next-action ref fields 와 직접 산출물 검사를 통해 같은 count/path 를 보존한다.
- 2026-06-02 재개 체크포인트: `out/route_investigation_queue.json` 의 next-action evidence refs 는 전부 top-level proof/missing/ref-count/failed-gate 필드를 갖고 weak-ref scan 이 `weak_ref_count 0` 이다. `python3 tools/verify_web_assets.py` 전체 검증도 통과하지만 `out/completion_audit.json` 은 여전히 `achieved=False` 이고 route promotion 은 blocked 다. 같은 세션에서 `tools/probe_runtime_trace_execution.py` 를 다시 실행해 `out/runtime_trace_execution_probe.*` 와 `out/runtime_trace_feasibility.*` 를 갱신했지만 `canCaptureTraceNow=False`/`canRunRuntimeTraceNow=False` 로 재확인됐다. 로컬 `SAVEDATA/` 와 `SaveData/` 에는 README 외 실제 `savedat*.dat`/zip 슬롯이 없어 P4 real selector `2:0` savedata proof 도 열 수 없다. 따라서 다음 productive input 은 real selector `2:0`/selected pointer `0x00540714`/`map1_01a -> map2_02d` 를 덮는 실제 savedat 슬롯, 또는 안정적인 Wine/QEMU watchpoint trace 환경, 또는 이를 대체하는 selected-root execution/strict source hotspot proof 다.
- 같은 재개 세션에서 `SAVEDATA/README.md` 와 `SaveData/README.md` 의 captured-save intake 안내도 맞췄다. 두 casing 모두 accepted slot name, required selector bytes `0x0002=0x02`/`0x0003=0x00`, expected selected pointer `0x00540714`, `--search-root` 검사 명령, browser `savedatScan`/`savedatUrl` 링크, `route_promotion_external_proof_handoff.html`, synthetic diagnostic exclusion, save 투입 뒤 route proof refresh chain 을 직접 싣는다. 또한 `tools/refresh_savedata_route_proof.py --search-root <file-or-dir-or-zip>` 를 추가해 `tools/scan_savedata_slots.py --search-root <file-or-dir-or-zip>` slot/search-root scan, real savedata scan, route queue/gate, strict/selected-root/predecessor/opcode24 proof packets, completion audit, blocker matrix, handoff, goal completion checklist, verifier 를 한 번에 재생성할 수 있게 했다. `.gitignore` 는 실제 `SAVEDATA/*`/`SaveData/*` slot contents 를 무시하고 README 만 versioned marker 로 남긴다. `out/route_promotion_gate.*`, `out/route_blocker_evidence_matrix.*`, `out/completion_audit.*`, `out/route_promotion_external_proof_handoff.*`, `out/goal_completion_checklist.*` 는 대표 external handoff regenerate command 를 이 래퍼로 노출하고, handoff captured-save package 는 intake README paths, gitignore guardrails, refresh command 를 직접 노출한다. `tools/verify_web_assets.py` 는 이제 README intake markers, refresh wrapper, handoff package fields, goal completion checklist refresh marker, gitignore guardrail 도 검사한다. 기본 로컬 `python3 tools/scan_savedata_slots.py` 재실행 결과는 여전히 `status=no-saves-found`, `foundCount=0`, `routeEvidenceCandidateCount=0` 이다. 반면 `python3 tools/refresh_savedata_route_proof.py --search-root data/public_savedata` 는 `out/savedata_slot_scan.*` 를 `status=valid-saves-without-current-selector`, found/valid `6/6`, `currentSelectorCandidateCount=0`, `realRouteEvidenceCandidateCount=0`, failed gates `current-selector-2-0,real-route-evidence-candidate` 상태로 재생성하고 verifier 를 통과한다. 두 상태 모두 blocked 이므로 completion audit 과 goal completion checklist 는 `achieved=False` 로 남는다.
- 2026-06-02 completion audit 재개 보강: `out/completion_audit.json` 은 이제 top-level `successCriteria`, `missingRequirements`, `blockingRequirements`, `nextRequiredInputs`, `routePromotionFailedGates`, `routePromotionHardBlockers`, `routePromotionNextRequiredEvidence` 를 직접 노출한다. 현재 success criteria 는 `resource-extraction`, `map-rendering`, `runtime-resource-loading` 만 complete 이고 `movement-input`, `normal-progression`, `event-dialogue-battle`, `completion-gate` 는 partial 이다. Blocking requirements 는 route promotion gate 다섯 개(`strictSourceHotspot`, `tileHotspotConfirmation`, `realSelector20Savedata`, `selectedRootExecution`, `runtimeTraceOrEquivalent`)이며 missing evidence 는 `strict source coordinate`, `tile hotspot confirmation`, `real selector 2:0 captured savedata`, `selected-root execution ref`, `runtime trace/equivalent selected-root proof` 로 고정된다. `nextRequiredInputs` 는 real selector `2:0` captured gameplay savedat, selected pointer `0x0059de30 -> 0x00540714` runtime/equivalent proof, strict `map1_01a -> map2_02d` source/tile-hotspot proof 를 직접 요구한다. `tools/verify_web_assets.py` 는 이 top-level completion summary 와 route hard blockers 를 검사하고, `python3 tools/refresh_savedata_route_proof.py --no-verify`, `python3 tools/verify_web_assets.py`, `git diff --check` 는 통과했다. 따라서 이 보강도 완료 신호가 아니라 `achieved=False` 를 더 명시적으로 보존하는 상태 문서화다.
- 2026-06-09 completion audit/checklist 정리: `out/completion_audit.json` 의 `nextRequiredInputs` 는 이제 실제로 투입 가능한 3개 입력만 남긴다. 1) selector `2:0` 및 selected pointer `0x00540714` 로 `map1_01a -> map2_02d` 를 덮는 captured gameplay savedat, 2) selected pointer `0x0059de30` 이 root `0x00540714` 를 실행하는 안정 runtime trace 또는 동등 proof, 3) `map1_01a -> map2_02d` 에 연결된 strict source coordinate/tile-hotspot proof 다. raw hard evidence 목록(`strict source coordinate`, `tile hotspot confirmation`, `real selector 2:0 captured savedata`, `selected-root execution ref`, `runtime trace/equivalent selected-root proof`)은 `routePromotionNextRequiredEvidence` 와 `hardMissingEvidence` 에만 남겨, 다음 세션에서 actionable input 과 gate label 을 혼동하지 않게 했다. `out/goal_completion_checklist.*` 도 같은 3개 next input 을 싣고, `out/completion_audit.html` 의 Prompt-To-Artifact checklist 와 `out/goal_completion_checklist.html` 의 artifact cell 은 `docs/`, `tools/`, `web/`, `out/` 경로를 클릭 가능한 링크로 제공하고, `out/*.*` wildcard 는 대표 `.html`, chunk wildcard 는 디렉터리 링크로 정규화해 prompt-to-artifact 증거를 바로 열 수 있게 했다. `tools/verify_web_assets.py` 는 `completion_audit.*` 와 `goal_completion_checklist.*` 가 `achieved=False`, route promotion `blocked`, next input 3개 상태와 대표 linked artifact 를 유지하는지 검사한다. `python3 -m py_compile tools/summarize_completion_audit.py tools/verify_web_assets.py`, `python3 tools/summarize_completion_audit.py`, `python3 tools/summarize_goal_completion_checklist.py`, `python3 tools/verify_web_assets.py` 는 8013 기준으로 통과했다.
- 2026-06-02 구현 방향 재정렬: route promotion gate 는 원본 정상 루트 승격용 provenance gate 로 유지하되, 웹 게임 구현은 그 게이트가 열릴 때까지 멈추지 않는다. `web/index.html` 의 `routeAssist` UI 를 디버그성 `보조`가 아니라 `후보 진행`/`후보 경로`/`프로토타입 진행`으로 바꾸고, 같은 행의 버튼 배치를 조정해 모바일에서 겹치지 않게 했다. `tools/verify_mobile_runtime_controls.py`, `tools/verify_mobile_browser_controls.py`, `tools/verify_web_assets.py` 도 같은 기대값으로 갱신했다. `python3 -m py_compile tools/verify_mobile_runtime_controls.py tools/verify_mobile_browser_controls.py tools/verify_web_assets.py`, `python3 tools/verify_web_assets.py`, `python3 tools/verify_mobile_runtime_controls.py`, `xvfb-run -a python3 tools/verify_mobile_browser_controls.py`, `git diff --check` 는 통과했다. 브라우저 smoke 에서 `후보 진행 켬`, 후보 경로 25개, `map1_02b -> map1_01a -> map2_02d -> map2_18d` 후보 진행이 확인됐다. 이 변경은 원본 루트 proof 를 승격하지 않으며, 목표를 `exe` 해제 근거 기반의 플레이 가능한 웹 게임 구현 쪽으로 되돌리는 체크포인트다.
- 2026-06-02/03/04 후보 save point 프로토타입: `web/index.html` 의 `세이브 후보` 메뉴는 계속 원본 save point proof 와 분리한다. 다만 후보가 현재 맵에 직접 연결된 경우에는 현재 위치/상태를 임시 저장 슬롯에 보존하는 prototype save 를 실행하게 했다. `map1_01a` 처럼 `global-review` 후보만 있는 경우에는 저장하지 않고 기존 읽기 전용 검토 대화(`세이브 후보 map1_01a: 6개`)를 유지한다. `map2_07e` 는 `event-dialogue-block-033` 이 `fieldMaps: map2_07e,map2_08e` 로 직접 연결되어 있어 메뉴 명령과 일반 Enter/A 액션 프롬프트 `Enter -> 세이브 후보 1` 양쪽에서 `후보 저장 map2_07e: 완료 (현재 맵 직접 연결)` 대화와 함께 localStorage runtime save payload 를 `map2_07e` 로 갱신한다. 저장 전에는 loaded/runtime 동료의 HP/MP 를 full 로 회복하고 상태이상을 비우는 prototype recovery 를 적용한다. 이 회복은 `originalRecoveryEventImplemented=False` 로 기록해 원본 여관/석상/회복 NPC 이벤트 구현으로 승격하지 않는다. 저장된 후보는 `save-point-candidate` 진행 기록 중 `saved=True` 인 이벤트만 완료로 보아 메뉴에서 `세이브 완료 1` 로 복원하고, source action prompt 도 `Enter -> 세이브 완료 1` 로 복원한다. 이를 위해 `tools/verify_candidate_save_point_browser.py` 를 추가했고, `out/candidate_save_point_browser_smoke.*` 는 `map1_01a` global review `saved=False` 와 `map2_07e` current-map candidate `saved=True recovered=True recoveredCount=1 curedStatusCount=2 autoSource=save-point-candidate payloadMap=map2_07e blockIds=event-dialogue-block-033`, action save `prompt=Enter -> 세이브 후보 1 saved=True recovered=True recoveredCount=1 curedStatusCount=2 autoSource=save-point-candidate`, quick-load 뒤 `save-point-candidates:map2_07e completed=True prompt=Enter -> 세이브 완료 1 selectMenuLabel=True restoredHp=36 restoredMp=8 restoredStatuses=none progressRestored=True` 를 기록한다. `tools/summarize_completion_audit.py` 와 `tools/verify_web_assets.py` 는 이 evidence 를 반영하지만, `originalSavePointRuntimeImplemented=False` 와 event/dialogue/battle `partial`, completion audit `achieved=False` 는 유지한다. 검증은 `python3 -m py_compile tools/summarize_completion_audit.py tools/verify_web_assets.py tools/verify_candidate_save_point_browser.py tools/verify_mobile_browser_controls.py tools/verify_mobile_runtime_controls.py`, `python3 tools/verify_mobile_runtime_controls.py`, `xvfb-run -a python3 tools/verify_candidate_save_point_browser.py`, `python3 tools/summarize_completion_audit.py`, `python3 tools/verify_web_assets.py` 가 통과했다. 통합 `tools/verify_mobile_browser_controls.py` 는 같은 세션에서 두 번 재시도했지만 기존 route-goal/route-return 구간에서 WebKitDriver 세션이 500/404 로 끊겨 이번 새 기능 검증은 별도 smoke 로 분리했다.
- 2026-06-02/03/04 후보 전투 프로토타입: `web/index.html` 의 전투 버튼은 현재 맵 계열 또는 `battleCandidate=` 쿼리에서 고른 source-backed 후보를 `전투 btl_*` 라벨과 title 로 노출하고, 전투 후보 데이터가 이미 로드된 상태에서는 일반 맵 액션 프롬프트도 `Enter -> 전투 btl_*` 로 같은 후보 전투를 시작한다. `encounter=1` 또는 런타임 메뉴 `전투 탐색 켜기` 를 사용하면 필드 이동 걸음 수를 세어 6걸음 뒤 현재 맵의 같은 source-backed 전투 후보로 자동 진입하는 prototype field encounter 도 동작한다. 이 상태는 `fieldEncounter` quick-save payload 와 URL `encounter=1` 로 보존되며, 진행 기록에는 `field-encounter`/`prototype-field-encounter` 로 남긴다. 필드 encounter 승리는 보상/레벨업은 적용하지만 `field-encounter-victory` 로 따로 기록하고, source event 후보를 완료시키는 `battle-victory` 는 남기지 않아 같은 맵에서 반복 전투가 가능하다(`battleVictoryCount=0`, `completionCompleted=False`, `button=전투 btl_b1`). 또한 EXE 근접 적 스프라이트 후보별 웹 prototype enemy profile 을 붙여 `zky_ao` 는 `푸른 마수` HP42/ATK4/DEF0/action 할퀴기/EXP7/drop 약초, `zjk_byk` 는 `백호 괴수` HP50/ATK5/DEF1/action 돌진/EXP9/drop 해독초 처럼 전투 이름/HP/공격/방어/행동/보상/드롭이 달라진다. 이 profile/action 은 `prototype-enemy-profile`/`prototype-enemy-action` 이며 원본 enemy row/stat/reward/drop/AI/status/formula 증거가 아니므로 `originalEnemyRowBound=False`, `originalStatsOrRewardsBound=False`, `originalRewardTableMapped=False`, `originalDropTableMapped=False`, `originalEnemyAiImplemented=False`, `originalStatusFormulaImplemented=False`, `originalCombatFormulaImplemented=False` 를 유지한다. 단, 원본 encounter table/진입 확률/전투 이벤트 실행은 아직 매핑하지 않았으므로 `originalEncounterTableMapped=False`, `originalEncounterRuntimeImplemented=False`, `originalEventDrivenBattleEntry=False` 를 명시한다. `battleCandidate=` URL 은 전투 데이터를 preload 하고 requested 후보 액션을 세이브 후보보다 우선해, 지정 후보 테스트가 저장 후보에 가로막히지 않게 했다. 전투 시작 시 `window.HWANSE_LAST_BATTLE_PROTOTYPE` 에 map, candidate id, block id, battle background, sample text, `sourceBacked=True`, `originalEventDrivenBattleEntry=False` 를 기록한다. 일반 후보 전투 승리 시에는 `battle-victory` 진행 기록을 남기고 바로 browser-local 임시 저장을 갱신해, 같은 후보는 제목 `이어하기` 나 임시 불러오기 뒤에도 `전투 완료 btl_*` 로 표시한다. 이 자동 저장 marker 는 `source=battle-victory`, `payloadMap=map1_02b`, `saveTile=11,12`, `completion.completed=True`, `runtimeMoney=75`, 약초 count 2 를 남긴다. 승리 보상 EXP 는 prototype 레벨업으로 이어져, 임계값을 넘긴 캐릭터의 level, HP/MP max, 기본 ATK/DEF/TECH/QUICK/LUCK 을 갱신하고 battle log 에 `Lv*` 를 남긴다. 이 레벨업은 웹 prototype 성장 공식이며 `originalLevelFormulaImplemented=False` 로 기록한다. 승리 보상 드롭은 `prototype-enemy-drop` 으로 `runtimeState.items` 에 누적되며 `zky_ao` 승리는 약초 count 를 0->1 로 올린다. 완료된 후보는 버튼/A/Enter 와 런타임 메뉴에서 재전투를 열지 않고 `battle-complete:event-dialogue-block-015` 완료 알림 대화로 막는다. 도주와 패배도 명시적인 후보 전투 outcome 으로 기록한다. 도주는 `battle-run` 진행 기록을 남기고 `도주했다.` 알림으로 맵에 복귀하며, 패배는 `battle-defeat` 진행 기록과 `패배했다.` 닫힘 메시지를 남긴다. 두 비승리 outcome 은 `battle-victory` 완료, 보상 money/EXP/drop, 원본 story flag mutation 으로 승격하지 않는다. `tools/verify_candidate_battle_browser.py` 를 추가해 독립 WebKit smoke 로 `map1_02b` 계열 후보 `event-dialogue-block-015:btl_b1` 이 버튼 클릭과 normal action path `prompt=Enter -> 전투 btl_b1 actionResult=True battleStartCount=1` 양쪽으로 전투 화면에 들어가고, `enemyName=푸른 마수 enemyHp=42 enemyAtk=4 enemyDef=0 enemyAction=할퀴기 enemyDrop=약초 enemyProfileSource=prototype-enemy-profile` 및 nonblank canvas/후보 요약을 남기는지 확인한다. 같은 smoke 는 `encounter=1` 에서 실제 `ArrowRight,ArrowLeft` 왕복 이동 6걸음으로 `movementSteps=6 steps=6/6 fieldEncounterCount=1 battleStartCount=1 source=prototype-field-encounter` 를 채워 같은 후보 전투가 자동 시작되고, 강제 승리 뒤에도 `fieldEncounterVictoryCount=1 battleVictoryCount=0 repeatable=True completionCompleted=False button=전투 btl_b1 drop=약초 dropSource=prototype-enemy-drop dropCount=1` 로 반복 가능 상태와 인벤토리 드롭이 유지되는지 확인한다. 또한 `map2_07e&battleCandidate=event-dialogue-block-041:btl_e1` 지정 후보가 `enemyName=백호 괴수 enemyHp=50 enemyAtk=5 enemyDef=1 enemyAction=돌진 enemyDrop=해독초 enemySprite=zjk_byk.cns` 를 쓰는지 확인하고, 별도 `event-dialogue-block-038:btl_n2` 상태이상 smoke 로 `enemyName=철갑 코뿔 enemyAction=독액 status=독 poisoned=Ataho poisonBefore=True item=해독초 poisonAfter=False itemCountAfter=0 enemyStatusInflicted=True originalStatusFormulaImplemented=False originalEnemyAiImplemented=False` 를 확인한다. `map1_02b` 일반 후보 전투를 짧게 승리 처리한 뒤 수동 저장 호출 없이 `전투 완료 btl_b1 battleVictoryCount=1 rewardExp=7 drop=약초 dropSource=prototype-enemy-drop expTotal=3 levelUpCount=1 levelAfter=2 nextExp=3/125 autoSaved=True autoSource=battle-victory saveMap=map1_02b saveTile=11,12 progressRestored=True`, 복원된 source action prompt `Enter -> 전투 완료 btl_b1`, `completedActionResult=True` 완료 알림, 런타임 메뉴 `전투 완료 btl_b1 menuNotice=battle-complete:event-dialogue-block-015` 가 저장/복원되는지도 확인한다. 또한 `runBattle` 은 `notice=도주했다. battleRunCount=1 battleVictoryCount=0 rewardGranted=False completionCompleted=False`, `defeatBattle` 은 `notice=패배했다. battleDefeatCount=1 battleVictoryCount=0 rewardGranted=False completionCompleted=False battleClosed=True` 를 확인한다. `out/candidate_battle_browser_smoke.*` 와 `out/completion_audit.*` 는 이 evidence 를 반영하지만 원본 event-driven 전투 진입, encounter table, enemy data/formula/reward/drop/story flag 는 계속 gap 으로 남기며 `achieved=False` 를 유지한다. 검증은 `python3 -m py_compile tools/verify_candidate_battle_browser.py tools/verify_mobile_runtime_controls.py tools/verify_web_assets.py tools/summarize_completion_audit.py`, `python3 tools/verify_mobile_runtime_controls.py`, `xvfb-run -a python3 tools/verify_candidate_battle_browser.py`, `python3 tools/summarize_completion_audit.py`, `python3 tools/verify_web_assets.py`, `git diff --check` 가 통과했다.
- 2026-06-02/04 후보 오브젝트 조사 프로토타입: `web/index.html` 에 `조사` 버튼과 A/Enter 조사 경로를 추가했다. `scene_events.js` 의 linked `z*.cns` 후보를 현재 맵/발밑 후보로 고르고, `map2_03l` 의 `zg_kni`, `zm_2`, `zs_rg` 처럼 같은 anchor 에 있는 후보는 일반 플레이 화면에도 passive NPC/오브젝트 스프라이트로 렌더하며, 보이는 스프라이트에 마우스를 올리면 pointer cursor 와 hover highlight 피드백을 주고 직접 클릭/탭해 `event-object-candidates:<map>` 대화로 조사할 수 있다. 키보드/패드 조사는 발밑 후보가 없으면 플레이어가 바라보는 앞 타일 후보를 `facing-object` 로 우선 잡고, 그 다음 기존 인접 후보를 fallback 으로 유지한다. 조사 시 `showEventObjectPrototypes` 를 켜서 완료/검토용 라벨을 표시하고, 같은 맵의 직접 대사 후보가 없으면 현재 타일셋 계열 대사 후보를 연결 요약으로 함께 보여준다. `map2_03l` 은 `map_l1/map_l2` 계열에서 `event-dialogue-block-004,032,041` 을 `연결 대사 후보 3개` 로 노출하고, 조사 결과를 끝까지 넘기면 첫 연결 후보 `event-dialogue-block-004` 대화로 이어진다. 이 경로는 broad 대사 후보 모드를 켜서 첫 연결 대사 완료 뒤 다음 후보 `event-dialogue-block-032` 를 계속 선택하고, 남은 연결 후보까지 완료하면 `dialogue-complete:map2_03l` 완료 알림을 열 수 있게 한다. 런타임 메뉴는 `조사 선택 N` 하위 메뉴로 후보를 고르게 하고 완료 알림은 버튼/목표/액션 경로로 유지한다. `window.HWANSE_LAST_EVENT_OBJECT_INSPECT` 와 `object-inspect` 진행 기록은 map/tile/scope/assets/anchors/scene ids, `linkedDialogueCount=3`, `originalLinkedDialogueRuntimeImplemented=False`, `originalEventObjectRuntimeImplemented=False` 를 남긴다. follow-up 대화 시작은 후보 대사 재생으로 `dialogue-candidate` 기록을 추가하고, 완독 시 `dialogue-complete` 기록과 `대사 완료 1/3` 또는 `대사 완료 3` 버튼 상태 및 saved prototypeProgress 를 남기지만 원본 NPC/object script 실행으로 승격하지 않는다. 이를 위해 `tools/verify_candidate_event_object_browser.py` 를 추가했고, `out/candidate_event_object_browser_smoke.*` 는 `map2_03l@11,11` 첫 진입에서 `passiveVisible=True prototype=False annotated=False candidates=3 loaded=3 rendered=3` 를 확인한 뒤, 보이는 스프라이트 캔버스 포인터 입력이 `event-object-candidates:map2_03l scope=pointer-object hoverCursor=pointer hoverAsset=zs_rg hit=zs_rg assets=zs_rg,zg_kni,zm_2 canvasPointer=True` 를 남기고, 아래 타일에서 위를 보고 누르는 정면 action 이 `event-object-candidates:map2_03l scope=facing-object prompt=Enter -> 조사 zg_kni 3개 assets=zg_kni,zm_2,zs_rg` 를 남기며, `조사 3` 버튼과 기존 A/Enter near-foot hotspot action 이 모두 `event-object-candidates:map2_03l scope=near-foot assets=zg_kni,zm_2,zs_rg prototype=True dialogueLinks=3 dialogueBlocks=event-dialogue-block-004,event-dialogue-block-032,event-dialogue-block-041` 를 남기는지 확인한다. 버튼 조사창 완료 뒤 `event-object-candidates:map2_03l -> event-dialogue-block-004 line=아타호 dialogueCandidateCount=1` follow-up 시작, `event-dialogue-block-004 completed button=대사 완료 1/3 next=event-dialogue-block-032 dialogueCompleteCount=1 savedDialogueCompleteCount=1 autoSaved=True autoSource=dialogue-complete` 완료/자동 저장, 그리고 남은 연결 후보 완료 뒤 `completed=event-dialogue-block-032,event-dialogue-block-041 button=대사 완료 3 notice=dialogue-complete:map2_03l dialogueCandidateCount=3 dialogueCompleteCount=3 savedDialogueCompleteCount=3 autoSaved=True autoSource=dialogue-complete` 전체 완료/자동 저장을 확인한다. 같은 smoke 는 새 페이지에서 quick-load 를 수행해 `loaded=True button=대사 완료 3 objectButton=조사 완료 3 notice=dialogue-complete:map2_03l dialogueButtonResult=True menuObject=조사 선택 3 directMenuIndex=-1 menuMode=object-candidate menuCandidateCount=3 dialogueCompleteCount=3 objectInspectCount=1` 로 완료 상태가 이어지는지 확인하고, 제목 화면 `이어하기 map2_03l 11,11` 경로에서도 같은 선택 메뉴 상태가 유지되는지 확인한다. 이 변경도 원본 NPC/object script 실행 proof 는 아니며, completion audit 은 `candidateEventObjectSmoke=True` 를 추가하되 `event-dialogue-battle=partial` 및 `achieved=False` 를 유지한다. 검증은 `python3 -m py_compile tools/verify_candidate_event_object_browser.py tools/verify_mobile_runtime_controls.py tools/verify_web_assets.py tools/summarize_completion_audit.py`, `python3 tools/verify_mobile_runtime_controls.py`, `xvfb-run -a python3 tools/verify_candidate_event_object_browser.py`, `python3 tools/summarize_completion_audit.py`, `python3 tools/verify_web_assets.py` 가 통과했다.
- 2026-06-03 후보 진행 기록/완료 상태 프로토타입: `web/index.html` 에 browser-local `prototypeProgress` 상태를 추가해 후보 대사, 조사, 세이브 후보, 전투 시작/승리 같은 웹 프로토타입 상호작용을 기록한다. 이 기록은 `runtimeState` 와 분리되어 savedat 없는 수동 플레이의 메뉴/동료 처리를 바꾸지 않고, `prototypeProgress` payload 로 임시 저장/불러오기에 보존된다. 맵 메뉴에는 `진행 기록` 항목을 추가해 `prototype-progress:<map>` 대화로 최근 기록을 확인할 수 있게 했다. 또한 조사 후보는 기록 뒤 `HWANSE_LAST_PROTOTYPE_COMPLETION`/`HWANSE_LAST_ACTION_PROMPT` 로 완료 상태를 계산해 `조사 완료 3` 버튼, `Enter -> 조사 완료 ...` 프롬프트, `done` 후보 렌더 라벨로 다시 화면에 반영한다. 완료된 조사 후보를 다시 누르면 새 `object-inspect` 기록을 만들지 않고 `event-object-complete:<map>` 알림 대화로 막는다. 기록/저장 payload 모두 `originalStoryFlagRuntimeImplemented=False` 를 명시해 원본 story flag 또는 event branch-state 구현으로 승격하지 않는다. 이를 위해 `tools/verify_candidate_progress_browser.py` 를 추가했고, `out/candidate_progress_browser_smoke.*` 는 `map2_03l@11,11` 조사 후보 `event-object-candidates:map2_03l` 이 `prototypeProgress` 에 자동 저장되며 `autoSaved=True autoSource=object-inspect` 를 남기고, 페이지 재진입 뒤 임시 불러오기에서 `prototype-progress:map2_03l progressRestored=True objectButton=조사 완료 3 renderDone=True menuCommand=showPrototypeProgress`, 완료 action `event-object-complete:map2_03l completedActionResult=True progressAfterAction=1`, 완료 버튼 `buttonCompletedActionResult=True progressAfterButton=1` 로 복원되는지 확인한다. completion audit 은 `candidateProgressSmoke=True` 를 추가하되 원본 event VM/story flag gap 과 `achieved=False` 를 유지한다.
- 2026-06-09 후보 진행 기록 story-state 리뷰 보강: `tools/verify_candidate_progress_browser.py` 는 이제 `map2_03l` 조사 완료 후 `prototypeStoryFlags` 도 함께 검증한다. `event-object-candidates:map2_03l` 의 `object-inspect` 기록은 runtime progress 와 저장 payload 양쪽에서 `storyFlags=1`, `savedStoryFlags=1`, key `story:object-inspect:map2_03l:event-object-candidates:map2_03l` 로 확인되고, 임시 불러오기 뒤 `prototype-progress:map2_03l` 리뷰 대화는 `스토리 상태 1개`, `최근 스토리 조사 map2_03l event-object-candidates:map2_03l` 라인을 보여준다. 현재 런타임 메뉴의 오브젝트 경로는 직접 완료 행이 아니라 `objectMenu=조사 선택 3` 하위 메뉴로 유지된다. 이 story-state 는 browser-local progress-derived flag 이며 원본 story flag offset/runtime mutation proof 는 계속 `originalStoryFlagRuntimeImplemented=False` 다.
- 2026-06-10 런타임 story-state 메뉴 보강: `web/game.html` 의 맵 런타임 메뉴에 `스토리 상태 N` 항목을 추가해 `prototypeProgress` 에서 파생된 browser-local story flag 를 `prototype-story-flags:<map>` 대화로 따로 확인할 수 있게 했다. `map2_03l` 조사 완료 복원 기준 새 대화는 `스토리 상태 map2_03l: 1개`, `종류 조사 1`, `#1 조사 map2_03l event-object-candidates:map2_03l`, `원본 story flag 실행 증명이 아니라 웹 프로토타입 진행 기록입니다.` 를 보여주고, `window.HWANSE_LAST_PROTOTYPE_STORY_FLAG_REVIEW` 는 `browserPrototypeStoryFlagReviewImplemented=True`, `storyFlagKeys=story:object-inspect:map2_03l:event-object-candidates:map2_03l`, `originalStoryFlagRuntimeImplemented=False` 를 남긴다. `tools/verify_candidate_progress_browser.py` 는 `storyFlagReview=prototype-story-flags:map2_03l`, `storyFlagReviewStatus=True`, `storyFlagReviewCounts=True`, `storyFlagMenuCommand=showPrototypeStoryFlags` 를 8013 WebKit smoke 로 검증하고, `tools/verify_web_assets.py` 는 정적 marker 와 smoke 문자열을 요구한다. 이는 진행/완료 상태를 게임 중 더 잘 확인하기 위한 브라우저-local UX 보강이며 원본 story flag offset/runtime mutation proof, event VM branch-state proof, route promotion 으로 승격하지 않는다.
- 2026-06-04 진행 목표 UX 보강: `prototypeProgress` 에 `prototypeObjectiveState()` 를 붙여 현재 웹-local 목표와 다음 행동을 같이 계산한다. 플레이 HUD 와 런타임 메뉴 왼쪽 상태 영역은 `목표 ...`/`다음 ...` 을 짧게 보여주고, 맵 메뉴 항목은 `진행 목표` 로 바뀌며, `prototype-progress:<map>` 대화는 `목표`, `다음`, `상태` 줄을 기존 최근 기록 앞에 표시한다. routeAssist 중에는 후보 목표/다음 이동/이어가기/전투 탐색/완료 확인을 안내하고, 일반 prototype 진행에서는 조사/대사/전투 진행 상태를 안내한다. 런타임 메뉴에는 `목표 실행` 명령도 추가해 현재 목표가 완료 안내라면 완료 대화를 열고, routeAssist 다음 이동이 있으면 다음 후보 경로를 실행하며, 아직 진행 기록이 없는 탐험 상태에서는 발밑 조사/대사/전투/상점 같은 hotspot action 을 먼저 실행한다. 이미 일반 진행 목표가 있으면 기존처럼 진행 검토 대화를 연다. `tools/verify_candidate_progress_browser.py` 는 `map2_03l` 첫 조사 시작을 실제 상단 `목표` 버튼 클릭(`quickObjectiveSource=objective-action-button`, `beforeObjectiveButtonHidden=False`, `beforeObjectiveButtonText=목표`)으로 열어 `objectiveAction=hotspot-action`, `event-object-candidates:map2_03l` 조사/자동 저장이 남는지 확인하고, 조사 완료 뒤 임시 저장/불러오기에서는 `objective=조사 진행`, `next=대사/전투/세이브 후보 확인`, 메뉴 라벨 `진행 목표 1`, `objectiveMenu=목표 실행`, `objectiveAction=progress-review`, 대화 라인 `목표 조사 진행`/`다음 대사/전투/세이브 후보 확인`/`상태 조사 1` 이 유지되는지 확인한다. 이 변경은 실제 플레이 중 “다음에 무엇을 할지”를 노출하고 바로 실행하는 웹 UX 개선이며, 원본 story flag/event VM 진행 상태 구현으로 승격하지 않는다.
- 2026-06-04 prototype 동료 합류/저장 흐름: savedat 없이 시작한 웹 게임에서 맵 메뉴가 `동료 선택 N` 서브메뉴를 노출하고, 선택 시 내부 `prototype-party-join` 경로가 `party-join-prototype` 진행 기록과 `HWANSE_LAST_PARTY_JOIN` marker 를 남기며 URL `party=rinshan,smash` 와 quick save payload 를 갱신한다. 임시 저장/불러오기 뒤에는 `members=rinshan,smash`, `label=린샹+스마슈`, `progressRestored=2`, 메뉴 `진행 목표 2` 로 복원된다. 또한 `event-dialogue-block-003` 대사 후보를 끝까지 보면 `prototype-dialogue-party-join` source 로 린샹이 합류하고, quick save/load 뒤 `dialogueCompleteRestored=1`, `partyJoinRestored=1`, `진행 목표 3` 으로 복원된다. 2026-06-08 부터 이 대사 기반 합류도 `objective=후보 대사 합류 완료 map1_02b`, `objectiveAction=dialogue-party-join-completion-notice`, `objectiveActiveId=dialogue-party-join-complete:map1_02b:event-dialogue-block-003`, `dialoguePartyNoticeFeedback=dialogue-party-join-completion-notice-feedback:대사 동료 합류 완료 1/1` 로 재확인된다. 이는 browser-local gameplay prototype 이며 원본 동료 합류 이벤트나 story flag/event VM runtime 구현으로 승격하지 않아 `originalEventVmRuntimeImplemented=False`, `originalPartyJoinEventImplemented=False`, `originalStoryFlagRuntimeImplemented=False` 를 유지한다. `tools/verify_candidate_party_join_browser.py` 와 `out/candidate_party_join_browser_smoke.*` 를 추가했고, `tools/summarize_completion_audit.py`/`tools/verify_web_assets.py` 는 `candidatePartyJoinSmoke=True` 와 새 gap 문구를 반영하되 completion audit `achieved=False` 를 유지한다.
- 2026-06-08 런타임 동료 선택 메뉴 보강: 맵 런타임 메뉴에 `동료 선택 N` 을 추가해 합류 가능한 prototype 동료를 `party-candidate` 하위 메뉴에서 직접 고를 수 있게 했다. 메인 메뉴의 개별 `동료 합류 린샹`/`동료 합류 스마슈` 직접 행은 제거해 플레이 메뉴 길이를 줄이고, 직접 합류 실행 함수는 대사 합류와 검증용 내부 경로로 유지한다. `tools/verify_candidate_party_join_browser.py` 와 `out/candidate_party_join_browser_smoke.*` 는 8013 기준 `map1_02b` 에서 메인 메뉴가 `menuCommands=동료 선택 2 directJoinRows=False` 를 남기고, `동료 선택 2` 를 열어 `동료 2/2 스마슈` 를 골라 `selected=smash`, `memberName=스마슈`, `selectionSource=prototype-party-candidate-menu`, `commandResult=True`, `selectResult=True`, `afterOpenMenuMode=party-candidate`, `afterMenuMode=main`, `joined=True`, `manualLabel=스마슈`, `members=smash`, `progressCount=1`, `autoSaved=True`, `autoSource=prototype-party-candidate-menu`, `joinFeedback=party-join-feedback:동료 합류 스마슈`, `joinFeedbackRender=True`, `partyJoinSound=menuConfirm`, `partyJoinSoundSrc=../extract_wlk/04.wav`, `partyJoinSoundPlayed=True` 를 남기는지 확인한다. 이는 browser-local 동료 선택/합류 표면이며 원본 party join event dispatch 나 story flag mutation proof 로 승격하지 않는다.
- 2026-06-08 런타임 상태 선택 메뉴 보강: 맵 런타임 메뉴에 `상태 선택 N` 을 추가해 loaded savedat 또는 prototype party 의 캐릭터를 `status-member` 하위 메뉴에서 직접 고른 뒤 한 명의 상태 대화를 열 수 있게 했다. 기존 전체 `상태 N` 요약 메뉴는 유지한다. `tools/verify_candidate_status_menu_browser.py` 와 `out/candidate_status_menu_browser_smoke.*` 는 8013 기준 public `flack3r-savedat2` 의 `map2_02d` 에서 `상태 선택 3` 을 열고 `상태 2/3 Rinshan` 을 골라 `selectionSource=prototype-status-member-menu`, `commandResult=True`, `selectResult=True`, `afterOpenMenuMode=status-member`, `afterMenuMode=main`, `active=status-member:map2_02d:Rinshan`, `progressCount=1`, `autoSaved=True`, `autoSource=status-member-menu-prototype`, `statusFeedback=status-member-menu-review-feedback:status-member-menu-prototype:status-member:map2_02d:Rinshan:상태 선택 Rinshan`, `statusFeedbackRender=True`, `statusSound=menuConfirm`, `statusSoundSrc=../extract_wlk/04.wav`, `statusSoundPlayed=True` 를 남기는지 확인한다. 이제 같은 선택 기록은 목표 상태 `objective=후보 상태 선택 완료 map2_02d` 로도 승격되고, `목표 실행` 은 `objectiveAction=menu-review-completion-notice`, `objectiveActiveId=status-member-review-complete:map2_02d`, `statusNoticeFeedback=status-member-menu-completion-notice-feedback:상태 선택 확인 완료 1/1`, `statusNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 남긴다. 이는 browser-local 상태 확인 표면이며 원본 equipment/status offset 이나 story flag runtime proof 로 승격하지 않는다.
- 2026-06-03 savedat 상태 메뉴 프로토타입: 맵 메뉴에 `상태` 항목을 추가해 loaded savedat 의 캐릭터 level, HP/MP, EXP, ATK/DEF/TECH/QUICK/LUCK, 상태명, 기술 수를 `status-menu:<map>` 대화로 확인할 수 있게 했다. savedat 없이도 현재 웹 프로토타입 동료 구성의 기본 상태를 볼 수 있지만, public savedat 로드 시에는 parsed character stat/skill fields 를 그대로 표시한다. 장비 offset, 원본 상태 flag, story flag 근거는 포함하지 않는다. `tools/verify_candidate_status_menu_browser.py` 를 추가했고, `out/candidate_status_menu_browser_smoke.*` 는 public `flack3r-savedat2` 로 savedat selector 기준 `map2_02d` 에 진입한 뒤 메뉴 `상태`가 `label=상태 3`, `source=savedat-character-stat-fields`, Ataho/Rinshan/Smashu HP/MP/ATK/DEF rows, `originalEquipmentOffsetsMapped=False`, `originalStoryFlagRuntimeImplemented=False` 로 열리는지 확인한다. completion audit 은 `candidateStatusMenuSmoke=True` 를 추가하되 original equipment/status/story flag gap 과 `achieved=False` 를 유지한다.
- 2026-06-04 새 게임 상태 메뉴 검증 개선: `tools/verify_candidate_status_menu_browser.py` 는 savedat 를 로드하지 않은 `map1_02b` 새 게임 상태에서 메뉴 `상태 1` 이 `status-menu:map1_02b`, `source=prototype-party-defaults`, `상태 prototype: 1명`, `Ataho Lv1 HP 36/36 MP 8/8`, `EXP 0/100 상태 정상 기술 0/0`, `ATK 0 DEF 0 TECH 0 QUICK 0 LUCK 0`, `loadedSaveSummary=False` 로 열리는지 확인한다. 이 흐름은 새 게임 UI/상태 표시 검증이며 원본 savedat status/story flag/equipment offset proof 로 승격하지 않는다.
- 2026-06-03 savedat 기술 메뉴 프로토타입: 맵 메뉴에 `기술` 항목을 추가해 loaded savedat 의 skill byte 해석과 EXE text table 기반 전투 기술 커맨드 해석을 같은 경로로 표시한다. 각 동료별 배운 기술 이름, 레벨, MP 비용, decoded slot/index/value, source table 을 `skill-menu:<map>` 대화로 보여주며, 장비 offset/story flag/원본 전투 공식 근거는 포함하지 않는다. `tools/verify_candidate_skill_menu_browser.py` 를 추가했고, `out/candidate_skill_menu_browser_smoke.*` 는 public `flack3r-savedat2` 로 savedat selector 기준 `map2_02d` 에 진입한 뒤 메뉴 `기술`이 `label=기술`, `names=돌려차기,던지기`, `source=savedat-skill-bytes-and-exe-text-tables`, `originalEquipmentOffsetsMapped=False`, `originalStoryFlagRuntimeImplemented=False` 로 열리는지 확인한다. completion audit 은 `candidateSkillMenuSmoke=True` 를 추가하되 original equipment offsets/story flag/combat formula gap 과 `achieved=False` 를 유지한다.
- 2026-06-08 런타임 기술 선택 메뉴 보강: 맵 런타임 메뉴에 `기술 선택 N` 을 추가해 loaded savedat 또는 prototype party 의 캐릭터를 `skill-member` 하위 메뉴에서 직접 고른 뒤 한 명의 기술 대화를 열 수 있게 했다. 기존 전체 `기술 N` 요약 메뉴는 유지한다. `tools/verify_candidate_skill_menu_browser.py` 와 `out/candidate_skill_menu_browser_smoke.*` 는 8013 기준 public `flack3r-savedat2` 의 `map2_02d` 에서 `기술 선택 3` 을 열고 `기술 1/3 Ataho 2/10` 을 골라 `selectionSource=prototype-skill-member-menu`, `learned=2/10`, `names=돌려차기,던지기`, `commandResult=True`, `selectResult=True`, `afterOpenMenuMode=skill-member`, `afterMenuMode=main`, `active=skill-member:map2_02d:Ataho`, `progressCount=1`, `autoSaved=True`, `autoSource=skill-member-menu-prototype`, `skillFeedback=skill-member-menu-review-feedback:skill-member-menu-prototype:skill-member:map2_02d:Ataho:기술 선택 Ataho 2/10`, `skillFeedbackRender=True`, `skillSound=menuConfirm`, `skillSoundSrc=../extract_wlk/04.wav`, `skillSoundPlayed=True` 를 남기는지 확인한다. 이제 같은 선택 기록은 목표 상태 `objective=후보 기술 선택 완료 map2_02d` 로도 승격되고, `목표 실행` 은 `objectiveAction=menu-review-completion-notice`, `objectiveActiveId=skill-member-review-complete:map2_02d`, `skillNoticeFeedback=skill-member-menu-completion-notice-feedback:기술 선택 확인 완료 1/1`, `skillNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 남긴다. 이는 browser-local 기술 확인 표면이며 원본 skill formula/combat formula/equipment offset/story flag runtime proof 로 승격하지 않는다.
- 2026-06-04 새 게임 기술 메뉴 표시 개선: savedat 를 로드하지 않은 새 게임 runtimeState 에서는 `skillMenuReviewBlock()` 이 더 이상 `기술 savedat` 로 고정 표시하지 않고 `기술 prototype` 으로 표시한다. `tools/verify_candidate_skill_menu_browser.py` 는 `map1_02b` no-savedat 상태에서 메뉴 `기술 0` 이 `skill-menu:map1_02b`, `source=prototype-party-defaults-and-exe-text-tables`, `기술 prototype: 0/0`, `Ataho Lv1 기술 0/0`, `배운 기술 없음`, `loadedSaveSummary=False` 로 열리는지 확인한다. 이는 새 게임 UI 명확화이며 원본 savedat skill byte/story flag/combat formula proof 로 승격하지 않는다.
- 2026-06-04 후보 장비 메뉴/장착 프로토타입: 맵 메뉴의 `장비 변경` 항목은 EXE text table 에서 추출된 장비명 후보 18개를 웹-local prototype weapon/armor 슬롯에 장착할 수 있게 한다. 장비 후보 설명은 메인 메뉴 직접 행이 아니라 `장비 변경 18` 서브메뉴 첫 항목 `장비 후보 설명` 에서 `equipment-menu:<map>` 대화로 확인한다. 이 장착은 캐릭터별 prototype 보너스를 `battleMemberStat()` 에 반영해 상태 메뉴와 후보 전투 ATK/DEF/TECH/QUICK/LUCK 계산에 사용하지만, savedat 소유/착용 offset 과 원본 장비 효과/story flag 는 구현하지 않고 `prototypeEquipmentEffectsImplemented=True`, `originalEquipmentOffsetsMapped=False`, `originalEquipmentEffectsImplemented=False` 를 명시한다. `tools/verify_candidate_equipment_menu_browser.py` 와 `out/candidate_equipment_menu_browser_smoke.*` 는 public `flack3r-savedat2` 로 `map2_02d` 에 진입한 뒤 `장비 변경 18 -> 장비 후보 설명` 이 `source=exe-text-table-equipment-candidates`, `table=0x0048b244`, `names=고양이 발톱,팬톰크로우 *,호랑이발톱 2,드레스`, `equipment-menu:map2_02d` 로 열리고 `directEquipmentReviewRows=False` 를 남기는지 확인한다. 같은 smoke 는 `장비 변경` 에서 `고양이 발톱` 을 Ataho weapon 으로 장착해 prototype ATK +4 가 적용되고, 임시 저장/불러오기 뒤 장착 슬롯/ATK/status menu 가 복원되며 `equipment-prototype progressCount=1` 이 남는지도 확인한다. completion audit 은 `candidateEquipmentMenuSmoke=True` 를 유지하되 장비 offset/original effect gap 과 `achieved=False` 를 유지한다.
- 2026-06-08 런타임 장비 대상 선택 메뉴 보강: 맵 런타임 메뉴에 `장비 대상 N` 을 추가해 `equipment-target` 하위 메뉴에서 Ataho/Rinshan/Smashu 를 먼저 고른 뒤 해당 캐릭터 장비만 보이게 했다. 기존 전체 `장비 변경 18` 메뉴는 유지한다. `tools/verify_candidate_equipment_menu_browser.py` 와 `out/candidate_equipment_menu_browser_smoke.*` 는 8013 기준 public `flack3r-savedat2` 의 `map2_02d` 에서 `장비 대상 3` 을 열고 `대상 1/3 Ataho 5` 를 골라 `selectionSource=prototype-equipment-target-menu`, `targetCounts=Ataho:5,Rinshan:6,Smashu:7`, `commandResult=True`, `selectResult=True`, `afterOpenMenuMode=equipment-target`, `afterMenuMode=equipment-equip`, `filteredItems=고양이 발톱,팬톰크로우 *,호랑이발톱 2,가죽 갑옷,흑장속` 를 남기는지 확인한다. 이는 browser-local 장비 대상 필터 표면이며 savedat 장비 소유/equipped-slot offset, 원본 장비 효과, story flag runtime proof 로 승격하지 않는다.
- 2026-06-04 새 게임 장비 장착 저장 개선: `tools/verify_candidate_equipment_menu_browser.py` 는 savedat 를 로드하지 않은 `map1_02b` 새 게임 상태에서도 `장비 변경` 메뉴가 열린 뒤 `고양이 발톱` 을 Ataho weapon 으로 장착할 수 있는지 확인한다. 기본 `prototype-new-game` Ataho 는 `atkBefore=0` 에서 장착 후 `atkAfter=4` 가 되고, 임시 저장/불러오기 및 타이틀 `이어하기 map1_02b 11,12` 뒤 `restoredAtk=4`, weapon slot 0, `equipment-prototype progressCount=1`, `quickLoadText=임시 불러오기`, `loadedSaveSummary=False` 가 유지된다. 이 흐름은 browser-local 장비 효과/진행 저장이며 savedat 장비 소유/equipped-slot offset, 원본 장비 효과, story flag runtime 으로 승격하지 않는다.
- 2026-06-05 장비 변경 화면 피드백: prototype 장비 장착 성공 시 런타임 메뉴 화면 위에 장비 변경 결과를 잠시 표시한다. `고양이 발톱` 장착은 `equipmentFeedback=equipment-change-feedback:Ataho:weapon:고양이 발톱:고양이 발톱 장착 / ATK+4 QUICK+1`, `equipmentFeedbackRender=True` 로 기록되며, `tools/verify_candidate_equipment_menu_browser.py` 는 savedat 장비 변경과 new-game no-loaded-savedat equipment equip 양쪽에서 `browserEquipmentChangeFeedbackImplemented=True` 로그/렌더 snapshot 을 확인한다. 이 변경은 장비 효과를 즉시 보이게 하는 웹 gameplay UX 이며 원본 savedat equipment ownership/equipped-slot offset, 원본 장비 효과, story flag proof 로 승격하지 않는다.
- 2026-06-04 후보 상점 메뉴/구매/판매 프로토타입: 맵 메뉴의 `상점 구매`, `상점 판매` 항목은 EXE item text table 의 savedat 아이템 6개와 event dialogue block 의 상점/구입 UI 텍스트 후보를 `shop-candidates:<map>` 대화 및 구매/판매 메뉴로 확인할 수 있게 한다. 상점 후보 설명은 메인 메뉴 직접 행이 아니라 `상점 구매 6` 서브메뉴 첫 항목 `상점 후보 설명` 에서 확인한다. 상점 후보가 현재 맵 또는 타일셋 계열에 연결된 경우, 미완료 직접 대사 후보를 먼저 처리한 뒤 일반 A/Enter action prompt 도 `Enter -> 상점 6` 을 띄우고 prototype 구매 메뉴를 연다. 설명 대화는 `source=exe-text-table-items-and-event-dialogue-shop-candidates`, 구매/판매 메뉴는 `source=prototype-shop-prices` 를 사용하며, 원본 상점 재고/가격표/구매 판매 실행은 구현하지 않고 `originalShopRuntimeImplemented=False`, `originalShopPriceTableMapped=False`, `originalShopInventoryMapped=False`, `originalMoneyMutationImplemented=False` 를 명시한다. `tools/verify_candidate_shop_menu_browser.py` 와 `out/candidate_shop_menu_browser_smoke.*` 는 `map4_08n` 에서 `상점 구매 6 -> 상점 후보 설명` 이 `table=0x0048b984`, `scope=tileset-family`, `items=약초,해독초,리프레시 워터,마법의 물약`, `contexts=event-dialogue-block-032,event-dialogue-block-038`, `shop-candidates:map4_08n`, `directShopReviewRows=False` 로 열리는지 확인하고, `dialogueGateBeforeShop=True firstPrompt=Enter -> 대사 1/2 firstBlock=event-dialogue-block-005 completedDialogue=event-dialogue-block-005,event-dialogue-block-026 vmBlocks=event-dialogue-block-005,event-dialogue-block-026 vmPartial=True,True vmRender=2,1 vmLiteral=0,8 vmSource=0x00030000,0x00030000` 뒤 normal action prompt 가 `kind=shop-candidate`, `opensMenuMode=shop-buy`, `canvasPointer=True` 로 구매 메뉴를 여는지도 확인한다. 같은 smoke 는 public `flack3r-savedat2` 를 로드해 `상점 구매` 에서 prototype price 12 로 `약초` 를 구입하고 `moneyBefore=983062 moneyAfter=983050 countBefore=3 countAfter=4`, 임시 저장/불러오기 뒤 `restoredMoney=983050 restoredCount=4`, `shop-buy-prototype progressCount=1` 을 확인한 뒤, `상점 판매` 에서 prototype price 6 으로 `약초` 를 판매해 `moneyBefore=983050 moneyAfter=983056 countBefore=4 countAfter=3`, 임시 저장/불러오기 뒤 `restoredMoney=983056 restoredCount=3`, `shop-sell-prototype sellProgressCount=1` 도 확인한다. completion audit 은 `candidateShopMenuSmoke=True` 를 유지하되 원본 shop runtime/price/inventory gap 과 `achieved=False` 를 유지한다.
- 2026-06-08 런타임 상점 선택 메뉴 보강: 맵 런타임 메뉴에 `상점 선택 N` 을 추가해 tileset-family 상점 후보가 여러 개일 때 후보 블록을 직접 고른 뒤 구매 메뉴로 들어갈 수 있게 했다. `tools/verify_candidate_shop_menu_browser.py` 와 `out/candidate_shop_menu_browser_smoke.*` 는 `map4_08n` 에서 `shop-candidate` 서브메뉴가 `menuCount=2` 로 열리고 `상점 1/2 event-dialogue-block-032` 를 선택하면 `selected=event-dialogue-block-032`, `scope=tileset-family`, `itemCount=6`, `contextCount=1`, `selectionSource=prototype-shop-candidate-menu`, `commandResult=True`, `selectResult=True`, `afterMenuMode=shop-buy`, `opensMenuMode=shop-buy`, `buyMenuSource=prototype-shop-prices`, `shopCandidateSource=exe-text-table-items-and-event-dialogue-shop-candidates` 를 남기는지 확인한다. 이 선택 메뉴는 browser-local 상점 후보 선택 표면이며 원본 shop runtime, price/inventory table, money mutation, story flag runtime proof 로 승격하지 않는다.
- 2026-06-04 새 게임 상점 구매/판매 저장 개선: `tools/verify_candidate_shop_menu_browser.py` 는 savedat 를 로드하지 않은 `map4_08n` 새 게임 상태에서도 미완료 직접 대사 후보를 먼저 완료한 뒤 `Enter -> 상점 6` prompt 를 canvas PointerEvent 로 눌러 구매 메뉴를 열고, 기본 `prototype-new-game` 소지금 60/약초 1 에서 약초를 prototype price 12 로 구입해 소지금 48/약초 2 로 바뀐 뒤 임시 저장/불러오기에서 `restoredMoney=48 restoredCount=2` 가 복원되는지 확인한다. 이어 `상점 판매` 에서 약초를 prototype price 6 으로 팔아 소지금 54/약초 1 이 되고, 다시 임시 저장/불러오기 및 타이틀 `이어하기 map4_08n 18,42` 에서 `restoredSellMoney=54 restoredSellCount=1`, `buyProgressCount=1`, `sellProgressCount=1`, `quickLoadText=임시 불러오기`, `loadedSaveSummary=False` 가 유지되는지도 확인한다. 이 흐름은 browser-local 상점 gameplay prototype 이며 원본 shop price/inventory/money mutation/story flag runtime 으로 승격하지 않는다.
- 2026-06-05 상점 거래 화면 피드백: prototype 상점 구매/판매 성공 시 메뉴 화면 위에 거래 피드백을 잠시 표시한다. 구매는 `shop-buy-feedback:buy:herb:약초 +1 / -12`, 판매는 `shop-sell-feedback:sell:herb:약초 -1 / +6` 으로 기록되며, `tools/verify_candidate_shop_menu_browser.py` 는 savedat 상점 흐름과 new-game no-loaded-savedat shop flow 양쪽에서 `buyFeedback=shop-buy-feedback:buy:herb:약초 +1 / -12/buyFeedbackRender=True`, `sellFeedback=shop-sell-feedback:sell:herb:약초 -1 / +6/sellFeedbackRender=True`, `browserShopTransactionFeedbackImplemented=True` 로그/렌더 snapshot 을 확인한다. 이 변경은 거래 결과를 즉시 보이게 하는 웹 gameplay UX 이며 원본 shop runtime/price/inventory/money mutation/story flag proof 로 승격하지 않는다.
- 2026-06-06 상점 구매/판매 실패 화면 피드백: prototype 상점 구매가 돈 부족이나 소지수 99개 제한으로 실패하거나, 보유 수량 0개인 아이템 판매가 실패할 때도 메뉴 notice 에만 묻히지 않고 같은 상점 feedback overlay 경로로 즉시 표시한다. public savedat 상점 smoke 는 `buyFailFeedback=shop-buy-failed-feedback:buy:herb:약초 돈 부족 5/12`, `buyFailFeedbackRender=True`, `buyFullFeedback=shop-buy-failed-feedback:buy:herb:약초 소지수 가득`, `buyFullFeedbackRender=True`, `sellFailFeedback=shop-sell-failed-feedback:sell:herb:약초 판매 없음`, `sellFailFeedbackRender=True` 를 확인하고, 실패 시 money/count 가 그대로이며 `shop-buy-prototype`/`shop-sell-prototype` 진행 기록, autosave, item WLK sound 를 만들지 않는지도 검증한다. 이 변경은 실패 조작까지 플레이 화면에서 분명히 보이게 하는 웹 gameplay UX 보강이며 원본 shop runtime/price/inventory/money mutation/story flag proof 로 승격하지 않는다.
- 2026-06-06 장비/상점 실행 EXE text-table provenance 보강: prototype 장비 장착과 상점 구매/판매 결과가 이름 문자열만 들고 끝나지 않도록, 실행 result, `recordPrototypeProgress()` detail, 자동 저장 payload, 화면 피드백 로그/렌더에 EXE text table 근거를 함께 남긴다. `고양이 발톱` 장착은 `equipment[0] 0x0048b244 -> 0x0048b52c`, `약초` 구매/판매는 `items[0] 0x0048b984 -> 0x0048ba7c` 를 `equipmentNameSource=exe-text-table-equipment` 및 `itemNameSource=exe-text-table-items` 로 보존하고, `tools/verify_candidate_equipment_menu_browser.py`, `tools/verify_candidate_shop_menu_browser.py`, `tools/verify_web_assets.py` 는 이 값이 메뉴 row/result/autosave/progress/feedback snapshot 에 모두 남는지 검증한다. 이 보강은 exe-derived 게임 구현 provenance 를 강화하지만, savedat 장비 소유/equipped-slot offset, 원본 장비 효과, 원본 상점 가격/재고/돈 mutation, story flag proof 로 승격하지 않는다.
- 2026-06-06 장비/상점 결과 WLK item sound 보강: prototype 장비 장착, 상점 구매, 상점 판매 성공 시 추출 WLK `item` 효과음 `extract_wlk/11.wav` 를 요청한다. `playSound()` 는 요청 이벤트를 반환하고, `tools/verify_candidate_equipment_menu_browser.py` 와 `tools/verify_candidate_shop_menu_browser.py` 는 각 액션 직전 사운드 로그를 초기화한 뒤 `equipmentSoundItemCount=1`, `buySoundItemCount=1`, `sellSoundItemCount=1` 및 `/extract_wlk/11.wav` 를 확인한다. 이 변경은 웹 gameplay 조작 피드백 강화이며 원본 DirectSound mixing/타이밍 완전 재현 증거는 아니다.
- 2026-06-07 장비/상점 feedback WLK sound marker 보강: `recordEquipmentChangeFeedback()` 은 이제 장비 장착/해제 overlay 를 만들 때 `item` WLK 사운드(`../extract_wlk/11.wav`)를 재생하고 feedback/render snapshot 에 `equipmentSound=item`, `equipmentSoundSrc=../extract_wlk/11.wav`, `equipmentSoundPlayed=True` 를 남긴다. `recordShopTransactionFeedback()` 도 성공한 구매/판매 feedback 에 `shopTransactionSound=item` 을 싣고 smoke report 는 `buySound=item`/`sellSound=item` 과 같은 src/played marker 를 요구한다. 실패 거래는 기존처럼 overlay 만 남기고 item 사운드와 progress/autosave 를 만들지 않는다. 이 보강은 장비/상점 조작의 화면 feedback 과 실제 WLK 효과음 증거를 같은 runtime path 에 묶는 웹 gameplay UX 개선이며, 원본 장비 offset/상점 가격표/money mutation/DirectSound timing proof 로 승격하지 않는다.
- 2026-06-08 장비 전투 피해 반영 검증 보강: `battleEquipmentEffectSummary()` 를 추가해 전투 공격/피격 hit/turn 결과에 prototype 장비 보너스, 장착 슬롯, `prototypeEquipmentBattleEffectImplemented=True`, `prototypeEquipmentBattleDefenseEffectImplemented=True`, `originalEquipmentEffectsImplemented=False` 를 남긴다. `tools/verify_candidate_equipment_menu_browser.py` 는 public `flack3r-savedat2` 상태에서 고양이 발톱 미장착/장착 공격을 같은 전투 후보로 비교해 `atkDelta=4`, `damageEquipped > damageBaseline`, `equipmentBonusAtk=4`, hit/turn marker `prototypeEquipmentBattleEffectImplemented=True` 를 확인하고, 흑장속 미장착/장착 피격도 비교해 `defDelta=4`, `incomingDamageEquipped < incomingDamageBaseline`, `equipmentBonusDef=4`, defense hit/turn marker `prototypeEquipmentBattleDefenseEffectImplemented=True` 를 확인한다. 이는 장비가 메뉴 숫자만 바꾸지 않고 실제 웹 전투 피해 계산에 들어가는지 고정하는 gameplay 검증이며, 원본 장비 효과/전투 공식/story flag proof 로 승격하지 않는다.
- 2026-06-06 장비 해제 결과 피드백/저장 보강: prototype 장비 변경에서 이미 장착된 같은 장비를 다시 선택하면 해제 액션의 실제 능력치 변화량을 `ATK-4 QUICK-1` 처럼 감소 방향으로 표시하고, result/progress/autosave/feedback 에 `quickBefore/quickAfter` 를 함께 남기게 했다. `tools/verify_candidate_equipment_menu_browser.py` 는 public `flack3r-savedat2` 장비 smoke 에서 `고양이 발톱` 장착을 임시 불러오기로 복원한 뒤 같은 행 `해제 Ataho 고양이 발톱 ATK+4 QUICK+1` 을 실행해 `equipmentUnequip action=unequip`, `weaponAfter=None`, `equipmentFeedback=equipment-change-feedback:Ataho:weapon:고양이 발톱:고양이 발톱 해제 / ATK-4 QUICK-1`, `equipmentFeedbackRender=True`, `equipmentSoundItemCount=1`, `autoSaved=True`, `autoSource=equipment-prototype` 를 확인한다. 이 변경은 장비 해제 조작이 플레이 화면/저장 payload 에 정확히 보이게 하는 웹 gameplay UX 보강이며, savedat 장비 offset, 원본 장비 효과, story flag proof 로 승격하지 않는다.
- 2026-06-05 후보 상점 완료 목표 실행 보강: savedat 없이 시작한 `map4_08n` 새 게임 상태에서 대사 gate 를 완료한 뒤 `약초` 구매/판매를 모두 수행해 `shop-buy-prototype` 과 `shop-sell-prototype` 진행 기록이 생기면 현재 목표가 `후보 상점 완료 map4_08n` / `완료 알림 확인` 으로 바뀌게 했다. 이 상태에서 `목표` 실행은 `shop-complete:map4_08n` 완료 알림을 열고, `objectiveAction=shop-completion-notice`, `objectiveActiveId=shop-complete:map4_08n` 를 남긴다. `tools/verify_candidate_shop_menu_browser.py` 는 직접 임시 불러오기 복원과 제목 화면 `이어하기 map4_08n 18,42` 복원 양쪽에서 구매 `약초 1->2 / 소지금 60->48`, 판매 `약초 2->1 / 소지금 48->54`, 목표 title/action/active id 를 확인한다. 이 보강은 완료된 웹 prototype 상점 거래를 현재 목표에서 바로 재확인하는 UX 개선이며, 원본 상점 재고/가격표/구매 판매 런타임, 원본 money mutation, story flag runtime proof 로 승격하지 않는다.
- 2026-06-07 후보 상점 완료 알림 피드백 보강: 완료된 `후보 상점 완료 map4_08n` 목표 실행이 알림 대화만 열고 끝나지 않도록, map 화면 위에 `shopNoticeFeedback=shop-completion-notice-feedback:상점 거래 완료 2/2`, `shopNoticeFeedbackRender=True`, `shopNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 남기는 상점 완료 overlay/WLK feedback 을 추가했다. `tools/verify_candidate_shop_menu_browser.py` 는 직접 임시 불러오기 복원과 제목 화면 `이어하기 map4_08n 18,42` 복원 양쪽에서 이 marker 를 확인한다. 이 보강은 완료 목표의 browser-local gameplay 피드백이며, 원본 상점 재고/가격표/구매 판매 런타임, 원본 money mutation, story flag runtime proof 로 승격하지 않는다.
- 2026-06-03 후보 대사 완료 프로토타입: `advanceDialogue()` 가 `event-dialogue-block-*` 후보의 마지막 줄을 넘길 때 `dialogue-complete` 진행 기록을 남기게 했다. 대사를 끝까지 본 후보는 임시 저장/불러오기 뒤에도 버튼/액션에서 `대사 완료 1/2` 로 복원되고, 대사 버튼 경로는 다음 미완료 후보 `event-dialogue-block-026` 을 우선 선택한다. 일반 프롬프트도 내부 `dialogue event-dialogue-block-*` 문구 대신 후보 순번과 완료 상태를 보여준다. 2026-06-04 보강으로 미완료 직접 대사 후보가 있을 때는 넓은 상점/전투 후보보다 대사 prompt/action 을 우선해 `map4_08n@11,11` 에서 `Enter -> 대사 1/2` 가 바로 `event-dialogue-block-005` 를 연다. 모든 후보를 완료하면 버튼/액션은 `대사 완료 2` 로 바뀌고, 다시 누를 때 후보 대사를 재생하지 않고 `dialogue-complete:map4_08n` 완료 알림 대화로 막는다. 런타임 main 메뉴에서는 중복 직행 완료 행을 숨기고 `대사 선택 2` 하위 메뉴만 노출한다. 단순 대화창 열람 기록(`dialogue-candidate`)과 완독 기록(`dialogue-complete`)을 분리한다. `tools/verify_candidate_dialogue_progress_browser.py` 를 추가했고, `out/candidate_dialogue_progress_browser_smoke.*` 는 `map4_08n` 의 하단 prompt 가 `prompt=Enter -> 대사 1/2 kind=dialogue-candidate blockId=event-dialogue-block-005 activated=True directDialogueBeforeShop=True` 로 상점 후보보다 직접 대사를 우선하는지 확인한 뒤, `event-dialogue-block-005` 를 canvas PointerEvent 로 0->1 진행하고 끝까지 넘겨 `button=대사 완료 1/2 next=event-dialogue-block-026 dialogueCompleteCount=1 progressRestored=True`, 이어서 `event-dialogue-block-026` 까지 완료한 뒤 `button=대사 완료 2 notice=dialogue-complete:map4_08n completedActionResult=True menu=대사 선택 2 directMenuIndex=-1 menuMode=dialogue-candidate menuCandidateCount=2 dialogueCompleteCount=2 originalStoryFlagRuntimeImplemented=False` 를 확인한다. 같은 smoke 는 제목 화면 `이어하기 map4_08n 11,11` 경로에서도 `titleContinue=True`, `quickLoadText=임시 불러오기`, `button=대사 완료 2`, `menu=대사 선택 2`, `dialogueCompleteCount=2` 가 유지되는지 확인한다. 이 변경도 원본 event VM/story flag proof 는 아니며 completion audit 은 partial/`achieved=False` 를 유지한다.
- 2026-06-03/04 후보 route 진행 저장 프로토타입: routeAssist 후보 출구를 실제로 탈 때 `route-candidate` 진행 기록을 남기고 target 맵 진입 직후 자동 저장하게 했다. `map1_01a@18,0` 의 top auto exit 로 `map2_02d@47,47` 에 들어가면 `map1_01a->map2_02d` 기록이 `prototypeProgress` 에 저장되고, `autoSaved=True autoSource=route-candidate` 로 임시 저장/불러오기 뒤에도 `map2_02d` 와 `진행 기록 1`/`후보 진행 1` 이 복원된다. 후보 경로 UI 는 같은 route row 를 `후보 진행 1/2` 로 표시하고, 저장된 progress 를 소스 타일에 다시 적용하면 action prompt 가 `Move/Enter -> 후보 완료 map2_02d`, 단일 후보 경로가 `후보 완료 1/1` 로 완료 상태를 보여준다. 복원된 routeAssist 상태에서 다음 후보 출구 `map2_02d@46,0 -> map2_18d` 를 이어서 타면 `map2_02d->map2_18d` 가 두 번째 `route-candidate` 로 누적되고, 자동 저장 뒤 `map2_18d` 와 `진행 기록 2`/`후보 진행 2`, 후보 경로 `후보 완료 2/2`, 다음 버튼 `완료` 가 복원된다. routeAssist runtime 상태도 quick save payload 에 보존한다. 이제 맵 런타임 메뉴도 `후보 진행 map2_02d` 로 routeAssist 를 시작하고 같은 메뉴에서 `후보 다음 map1_01a` 를 노출하므로, 상단 디버그 버튼 없이 인게임 메뉴만으로 후보 경로를 따라갈 수 있다. `tools/verify_candidate_route_progress_browser.py` 를 추가했고, `out/candidate_route_progress_browser_smoke.*` 는 `routeMenuStart=map1_02b menu startItem=후보 진행 map2_02d nextItem=후보 다음 map1_01a`, `routeCandidateCount=1 autoSaved=True autoSource=route-candidate pathProgress=후보 진행 1/2` 첫 홉, source prompt `Move/Enter -> 후보 완료 map2_02d pathProgress=후보 완료 1/1`, `routeCandidateCount=2 autoSaved=True autoSource=route-candidate pathProgress=후보 완료 2/2 progressRestored=True originalRoutePromotionImplemented=False` 체인 복원을 확인한다. 같은 smoke 는 제목 화면 `이어하기 map2_18d 47,47` 경로에서도 `titleContinue=True`, `quickLoadText=임시 불러오기`, `routeGoal=map2_18d`, `routeCandidateCount=2`, `pathProgress=후보 완료 2/2` 가 유지되는지 확인한다. 이 역시 원본 strict hotspot/selected-root 실행 proof 가 아니므로 normal route promotion 과 completion audit 은 blocked/`achieved=False` 를 유지한다.
- 2026-06-04 제목 화면 시작/이어하기/routeAssist 개선: 제목 화면은 Canvas 안에 기본 플레이 메뉴 `처음부터` 를 그리고, 임시 저장이 있으면 `이어하기` 를 추가한다. `후보 진행` 은 도구/디버그 UI 가 열린 상태나 routeAssist 쿼리 상태에서만 제목 메뉴에 나타나며, 일반 collapsed 플레이 화면에서는 routeAssist/루트/근거/자산/세이브 스캔/load savedat뿐 아니라 대사/조사/전투/전체 지도 단축 버튼도 `도구` 뒤로 숨긴다. 모바일 접근성을 위해 별도 `☰` 버튼을 추가해 숨겨진 단축 버튼 없이도 런타임 메뉴를 열 수 있게 했다. 기본 Enter 시작은 확인된 시작 지점 `map1_02b@11,12` 로 유지하고, 임시 저장이 있으면 메뉴와 상단 quick-load 버튼 모두 `이어하기` 를 노출해 같은 quick save payload 를 `quickLoadRuntime()` 으로 복원한다. 키보드/모바일 A뿐 아니라 Canvas 메뉴 행 직접 클릭도 선택 항목을 실행한다. 또한 제목 화면의 `후보 진행` 선택과 상단 버튼은 후보 출구로 바로 워프하지 않고 `map1_02b@11,12` 로 진입한 뒤 `trialTransitions=routeAssist&routeGoal=map2_02d` 를 켜고 후보 경로 `다음` 버튼을 노출한다. 맵 런타임 메뉴에는 `제목` 명령을 추가해 전투/대사/메뉴 입력 상태와 URL query 를 정리하고 타이틀로 돌아갈 수 있게 했다. 타이틀에서 `처음부터`/`후보 진행` 을 다시 시작할 때는 이전 routeAssist/runtime/savedat/prototypeProgress/manual party 메모리 상태를 새 세션으로 초기화하고, 임시 저장 슬롯은 `이어하기` 용으로만 유지한다. `tools/verify_title_start_browser.py` 는 기본 Enter 시작, 런타임 메뉴의 제목 복귀, 제목 메뉴 `이어하기`, 도구 상태의 Canvas 메뉴 `후보 진행`, 제목 화면 routeAssist 버튼 경로를 같은 smoke 안에서 확인한다. 이 변경도 browser-local 임시 저장/routeAssist 편의 기능이며 원본 `map1_01a -> map2_02d` route promotion 으로 승격하지 않는다.
- 2026-06-04 기본 플레이 HUD 개선: 디버그 오버레이가 꺼진 맵 화면의 하단 창 영역에 `drawPlayHud()` 를 추가해 현재 맵/좌표, 파티 HP, 소지금, 필드 전투 카운트, 진행 기록 수, 임시 저장 존재 여부를 표시한다. `tools/verify_title_start_browser.py` 는 타이틀에서 `처음부터` 로 들어간 기본 지도 화면의 `playHudLines` 가 `map1_02b 11,12`, `Ataho HP`, `저장 없음` 을 포함하는지 확인하고, 같은 위치를 `quickSaveRuntime()` 한 뒤 `저장 있음` 으로 바뀌는지도 확인한다. 이 HUD 는 플레이 가시성 개선이며 원본 save UI/event flag/runtime proof 로 승격하지 않는다.
- 2026-06-04 새 게임 runtimeState 개선: `처음부터`/제목 `후보 진행`/savedat 없는 URL 진입에서 `createPrototypeRuntimeState()` 가 기본 소지금 60, Ataho 기본 HP/MP, EXE item text table 기반 6개 아이템 슬롯, 약초 1개를 가진 웹-local 상태를 만든다. 따라서 savedat 를 직접 로드하지 않아도 상점 구매/판매, 장비 변경, 인벤토리 사용, 전투 보상/드롭, 임시 저장/불러오기가 같은 상태 모델을 쓴다. 수동 동료 구성이 바뀌면 `ensurePrototypeRuntimeState()` 가 현재 동료 목록과 기존 HP/MP/장비/아이템 상태를 병합한다. `tools/verify_title_start_browser.py` 는 `?map=map1_02b&startTile=11,12` 직접 URL 진입의 `playHudLines` 가 `소지금 60` 을 포함하는지, 그리고 새 게임 quick save payload 에 `runtimeState`, `money=60`, `Ataho`, `herb:1` 이 들어가는지 확인한다. 이 상태는 `source=prototype-new-game` 인 browser-local gameplay state 이며 원본 savedat offset/story flag/event VM proof 로 승격하지 않는다.
- 2026-06-04 새 게임 도구 사용 저장 개선: 맵 메뉴의 인벤토리 도구 사용 성공 경로가 `item-use-prototype` 진행 기록과 `HWANSE_LAST_INVENTORY_ITEM_USE` marker 를 남기고, `prototype-item-effect` source 로 아이템 수량/HP/MP/status 전후값을 기록한다. `tools/verify_title_start_browser.py` 는 새 게임 Ataho 를 HP 24 로 낮춘 뒤 `약초 x1` 을 메뉴에서 사용해 HP 36, 약초 0개가 되고, 이 상태를 quick save 한 뒤 runtimeState 를 일부러 오염시켜도 quick load 로 HP 36/약초 0개/진행 기록 1 이 복원되는지 확인한다. 같은 smoke 는 제목 화면 `이어하기 map1_02b 11,12` 경로에서도 `quickLoadText=임시 불러오기`, HP 36/36, 약초 0개, `item-use-prototype` 1, `loadedSaveSummary=False` 가 유지되는지 확인한다. 이 역시 browser-local 아이템 효과/진행 저장이며 원본 아이템 공식, savedat status/story flag offset, event VM proof 로 승격하지 않는다.
- 2026-06-04 런타임 메뉴 스크롤/직접 선택 개선: 후보 대사/조사/세이브/전투/상태/기술/장비/상점/저장/불러오기/제목 항목이 누적되면서 오른쪽 메뉴가 10줄 고정 렌더링 밖으로 잘리던 문제를 줄였다. `runtimeMenuWindow()` 는 선택된 항목 기준으로 8개 행 window 를 잡고, 메뉴 오른쪽에는 현재 `n/total` 과 위/아래 표시를 그린다. 또한 `runtimeMenuItemIndexAtPoint()` 와 canvas pointer handler 를 추가해 메뉴가 열린 상태에서는 오른쪽 메뉴 행을 마우스/터치로 직접 눌러 선택/실행할 수 있다. `tools/verify_title_start_browser.py` 는 아래쪽 `제목` 항목을 선택할 때 scroll window 가 `제목` 을 visible label 로 포함하고, 같은 행의 pointer hit-test 와 canvas pointerdown 으로 제목 복귀가 실행되는지 확인한다. 이 변경은 조작성 개선이며 completion audit 의 원본 route/event proof gap 은 그대로 유지한다.
- 2026-06-08 런타임 도구 선택 서브메뉴 개선: 맵 런타임 메인 메뉴에 `도구 선택 N` 항목을 추가하고, 메인 메뉴 끝에 직접 붙던 `약초 xN` 같은 도구 행은 제거했다. 이제 필드 도구 사용은 `도구 선택 N` 이 여는 `inventory-item` 서브메뉴에서만 고르며, `약초 x2` 를 고르면 `HWANSE_LAST_INVENTORY_ITEM_MENU_SELECTION` 이 `source=prototype-inventory-item-menu`, `opensMenuMode=item-target`, `targetCount=3`, `originalInventoryMenuRuntimeImplemented=False` 를 남긴 뒤 기존 `inventory-item-target-selection` 으로 이어진다. `tools/verify_title_start_browser.py` 는 새 게임 `map1_02b` 에서 Ataho/Rinshan 이 모두 다친 상태로 `도구 선택 1 -> 약초 x2 -> Rinshan` 을 실행해 HP 8->38, 약초 2->1, `item-use-prototype` auto-save, `inventoryFeedback=inventory-item-use:herb:약초 HP +30`, `prototypeInventoryItemMenuImplemented=True`, `prototypeInventoryItemTargetSelectionImplemented=True` 를 확인한다. `tools/verify_mobile_browser_controls.py` 의 savedat 필드 도구 검증도 메인 메뉴 직접 도구 행 대신 `도구 선택` 서브메뉴를 열어 `약초 x3` 를 선택한다. 이 변경은 플레이 메뉴 조작성 개선이며 원본 inventory menu runtime, 아이템 공식, story flag proof 로 승격하지 않는다.
- 2026-06-04 전투 HUD 직접 선택 개선: 전투 화면 하단 명령도 `battleHudChoiceWindow()`/`battleHudChoiceIndexAtPoint()` 로 선택 window 와 pointer hit-test 를 공유하게 했다. 전투 중 canvas 의 명령 행을 마우스/터치로 누르면 해당 공격/방어/도구/도주 또는 도구 메뉴 항목을 직접 실행한다. `tools/verify_candidate_battle_browser.py` 는 `map1_02b` 후보 전투에서 `공격` 행에 PointerEvent 를 보내 hit index 가 attack command 를 가리키고 적 HP 가 감소하는지 확인한다. 이 역시 웹 조작성 개선이며 원본 전투 command/event VM 구현 완료로 승격하지 않는다.
- 2026-06-05 전투 hit feedback 보강: 성공한 플레이어 공격/기술과 적 반격은 `HWANSE_BATTLE_HIT_EFFECT_LOG` 와 `HWANSE_LAST_BATTLE_HIT_EFFECT` 에 attacker/target/damage/HP 전후값을 남기고, 전투 canvas 에 260ms flash 와 4px shake 를 짧게 그린다. 같은 타격은 `HWANSE_BATTLE_DAMAGE_TEXT_LOG` 에도 기록되어 620ms floating damage number 로 표시된다. `tools/verify_candidate_battle_browser.py` 는 `map1_02b` 후보 전투의 canvas pointer attack 에서 `hitEffectTargets=enemy,party`, `hitEffectDuration=260`, `hitEffectShake=4`, `browserHitEffect=True`, `renderTarget=party`, `damageTextTargets=enemy,party`, `damageTextDuration=620`, `damageTextRender=enemy,party`, `browserDamageText=True` 를 확인한다. 이는 웹 prototype 타격 피드백이며 원본 전투 공식/연출 타이밍/story flag proof 로 승격하지 않는다.
- 2026-06-09 전투 hit sprite feedback 보강: 위 hit overlay 는 이제 extracted `btl_etc.cns` PNG(`battle_effects`, `../out/btl_etc.png`) bottom row 64x32 6-frame burst 를 함께 그린다. `recordBattleHitEffect()` 와 render snapshot 은 `effectSourceCns=btl_etc.cns`, descriptor table `0x00442d95` row 3, `effectFrameCount=6`, `spriteDrawn=True`, `browserHitSprite=True`, `originalBattleEffectTimingImplemented=False` 를 남긴다. `tools/verify_candidate_battle_browser.py` 는 8013 기준 canvas pointer attack 에서 `hitEffectSprite=battle_effects`, `hitEffectSpriteSource=btl_etc.cns`, `spriteDrawn=True`, `browserHitSprite=True` 를 검증하고, `tools/verify_web_assets.py`/`tools/summarize_completion_audit.py` 는 같은 marker 를 completion audit evidence 에 보존한다. 이는 browser-local extracted sprite visual feedback 이며 원본 battle-effect timing/combat formula/story flag proof 로 승격하지 않는다.
- 2026-06-04 대화창 chrome/canvas/모바일 B 진행 개선: 일반 대화창 헤더는 내부 `event-dialogue-block-*` ID 를 화면에 그대로 노출하지 않고 `대화 1/13`, `대사 완료 ...`, `전투 완료 ...` 같은 플레이용 라벨을 그린다. 대화가 열린 동안 canvas pointerdown 은 지도/메뉴/전투/조이스틱 처리보다 먼저 `advanceDialogue()` 로 소비되므로 대화창 자체를 마우스/터치로 눌러 다음 줄로 넘길 수 있다. `tools/verify_candidate_dialogue_progress_browser.py` 는 `event-dialogue-block-005` 를 열었을 때 화면 chrome 이 `header=대화 1/13 internalIdHidden=True` 를 남기는지, 모바일 `B` 로 닫아 `mobileB=True active=False completeCount=0 restarted=True reopened=event-dialogue-block-005` 가 되는지, 다시 열린 첫 줄에서 canvas PointerEvent 로 index `0->1` 이 진행되며 이후 completion/save/load 흐름이 유지되는지 확인한다. 이 변경도 후보 대사 UX 개선이며 원본 event VM 실행 proof 로 승격하지 않는다.
- 2026-06-04 action prompt 직접 선택 개선: 지도 화면에 그려진 `Enter -> ...` action prompt 의 rect 를 `actionPromptRect()`/`actionPromptHitAtPoint()` 로 계산하고, canvas pointerdown 이 그 영역에 들어오면 Enter/A 와 같은 `activateHotspotAtFoot()` 경로를 실행한다. 따라서 마우스/터치로 화면 하단 prompt 를 눌러 조사/상점/세이브/전투/대사/맵 전환 후보를 실행할 수 있다. `tools/verify_candidate_shop_menu_browser.py` 는 `map4_08n` 의 직접 대사 gate 를 완료한 뒤 `Enter -> 상점 6` prompt 중앙에 PointerEvent 를 보내 `shop-buy` 메뉴가 열리고 구매/판매 저장 흐름이 유지되는지 확인한다. 이 역시 웹 조작성 개선이며 원본 event VM/상점 구현 proof 로 승격하지 않는다.
- 2026-06-03/04 confirmed 맵 전환 진행 저장 프로토타입: 이미 review confirmed 인 일반 전환도 실제 플레이 진행으로 남기게 했다. `map1_02b@11,12` 에서 `Move/Enter -> map1_01a...confirmed` action prompt 를 Enter/A 또는 canvas pointer 로 실행하면 `map1_01a` 로 들어가고, `map-transition` 진행 기록 `map1_02b->map1_01a` 가 `prototypeProgress` 에 저장된다. target 맵 진입 직후 자동 저장 payload 는 `payloadMap=map1_01a`, `mapTransitionCount=1`, `autoSaved=True`, `autoSource=map-transition`, `transitionReviewState=confirmed` 를 보존한다. confirmed event 전환 실행 시에는 `HWANSE_LAST_CONFIRMED_EVENT_TRANSITION` 에 source/target/trigger/scene record 근거를 남기고 `originalSceneRecordBacked=True`, `routeAssistActive=False` 를 WebKit smoke 가 확인한다. 제목 화면으로 돌아가도 `이어하기 map1_01a...` 행이 같은 payload 를 복원해 `prototype-progress:map1_01a`, `진행 기록 1`/`맵 전환 1`, 상단 `임시 불러오기` 상태가 유지된다. 직접 불러오기 뒤 원래 소스 타일로 돌아가면 prompt 가 `Move/Enter -> 전환 완료 map1_01a...confirmed` 로 완료 상태를 보여준다. 전환 실행은 `HWANSE_LAST_TRANSITION_EFFECT` 에 `transitionEffect=map1_02b->map1_01a`, `effectTrigger=action/movement`, `fadeMs=420`, `browserFade=True` 를 남기고 canvas fade overlay 를 짧게 그린다. `tools/verify_candidate_transition_progress_browser.py` 와 `out/candidate_transition_progress_browser_smoke.*` 가 routeAssist 없이 prompt `canvasPointer=True` action path, title `이어하기` restore `titleContinue=True`, movement-triggered confirmed transition path `trigger=movement direction=...`, fade marker, 자동 저장/불러오기, `progressRestored=True`, `sourcePrompt=Move/Enter -> 전환 완료 map1_01a...confirmed`, `originalStoryFlagRuntimeImplemented=False`, `originalTransitionFadeTimingImplemented=False` 를 확인한다. 이것도 원본 story flag 실행/route promotion/fade timing 증명은 아니므로 completion audit 은 `achieved=False` 를 유지한다.
- 2026-06-05 confirmed 맵 전환 완료 목표 실행 보강: `map-transition` 진행 기록이 있는 `map1_01a` 도착 상태에서 현재 목표가 `후보 전환 완료 map1_01a` / `완료 알림 확인` 으로 바뀌고, `목표` 실행이 `transition-complete:map1_01a` 완료 알림을 열게 했다. `tools/verify_candidate_transition_progress_browser.py` 는 직접 `Move/Enter -> map1_01a...confirmed` 전환 직후와 제목 화면 `이어하기 map1_01a` 복원 뒤 양쪽에서 `objectiveAction=map-transition-completion-notice`, `objectiveActiveId=transition-complete:map1_01a`, route `map1_02b->map1_01a`, `transitionReviewState=confirmed`, `originalSceneRecordBacked=True`, `originalRoutePromotionImplemented=False` 를 확인한다. 이 보강은 confirmed 전환 진행 기록을 현재 목표에서 재확인하는 웹 UX 개선이며 원본 story flag/route promotion proof 로 승격하지 않는다.
- 2026-06-04 후보 전투 새 게임 상태 검증 보정: 기본 `prototype-new-game` runtimeState 가 생긴 뒤 전투 smoke 는 필드 encounter/일반 후보 전투의 약초 드롭 누적을 `dropCount=2`, `runtimeMoney=75`, `loadedSaveSummary=False` 로 확인한다. 도주와 패배는 더 이상 runtimeState 부재를 기대하지 않고, 기본 `runtimeMoney=60`, `runtimeExp=0` 이 보상 없이 유지되며 `battleVictoryCount=0`, `rewardGranted=False`, `completionCompleted=False` 인지만 확인한다. 이 보정은 새 게임 상태 모델과 전투 outcome 검증을 맞춘 것이며 원본 enemy row/reward/formula/story flag proof 로 승격하지 않는다.
- 2026-06-04 전투 패배 후 플레이 지속성 개선: 후보 전투에서 파티가 전멸해 `패배했다.` 로 맵에 돌아올 때, 웹 prototype recovery 가 첫 런타임 파티원 Ataho 를 HP 1로 되살려 이동/저장/회복 후보 테스트를 계속할 수 있게 했다. `HWANSE_LAST_BATTLE_DEFEAT_RECOVERY` 는 `source=prototype-battle-defeat-recovery`, `recovered=True`, `target=Ataho`, `hp=0->1`, `originalStoryFlagRuntimeImplemented=False` 를 남긴다. `tools/verify_candidate_battle_browser.py` 는 패배가 여전히 `battle-defeat` 진행 기록만 남기고 `battleVictoryCount=0`, `rewardGranted=False`, `completionCompleted=False`, `runtimeMoney=60`, `runtimeExp=0` 을 유지하면서도 맵 복귀 뒤 Ataho HP 1이 되는지 확인한다. 이 회복은 browser-local 패배 복구 UX이며 원본 revive/inn/story flag/event VM proof 로 승격하지 않는다.
- 2026-06-04 후보 목표 인게임 메뉴/HUD 개선: 맵 런타임 메뉴에 `후보 목표 25` 서브메뉴를 추가해 상단 routeAssist select 없이도 후보 경로 목표를 고를 수 있게 했다. 목록은 `map2_18d 0/3` 처럼 목표 맵과 진행도를 표시하고, 선택하면 `trialTransitions=routeAssist`, `routeGoal=<target>`, `routePathSelect` 값과 URL query 를 동기화한 뒤 같은 메뉴에서 `후보 다음 map1_01a` 를 노출한다. 플레이 HUD 도 `후보 map2_18d  다음 map1_01a` 처럼 현재 후보 목표/다음 이동 대상을 표시한다. `tools/verify_candidate_route_progress_browser.py` 는 `map1_02b` 새 게임 상태에서 `후보 목표 25` 를 열어 `map2_18d` 를 선택하고 `routeGoal=map2_18d routePathValue=map2_18d runtimeMenuRouteGoal=True` 와 HUD route line 을 확인한다. 이 변경은 상단 디버그 UI 의존도를 줄이는 플레이 편의 기능이며 원본 route promotion proof 로 승격하지 않는다.

- 2026-06-04 런타임 서브메뉴 취소 개선: 장비/상점/후보 목표 같은 런타임 서브메뉴에서 `Esc`/`I`, 모바일 `☰`, 또는 새 모바일 `B` 버튼을 누르면 전체 메뉴를 바로 닫지 않고 먼저 메인 메뉴로 돌아가며, 메인 메뉴에서 한 번 더 누르면 닫히게 했다. 메뉴 하단 안내도 서브메뉴에서는 `I/Esc 뒤로`, 메인 메뉴에서는 `I/Esc 닫기` 로 바뀐다. `B` 는 대화 닫기, 전투 아이템 메뉴 닫기/전투 종료, 전체 지도 닫기도 담당한다. `tools/verify_title_start_browser.py` 는 새 게임 `map1_02b` 에서 `shop-buy` 메뉴를 연 뒤 `submenuCancel=shop-buy->main->False`, `mobileMenuCancel=shop-buy->main->False`, `mobileBCancel=shop-buy->main->False` 흐름을 확인한다. 이 변경은 조작성 개선이며 원본 event VM/route proof 로 승격하지 않는다.

- 2026-06-04 상단 임시 저장 UI 정리: 기본/도구 화면의 상단 임시 저장 버튼 라벨을 영어 `quick save`/`quick load` 대신 `임시 저장`/`임시 불러오기` 로 바꿨다. 제목 화면의 이어하기 버튼은 계속 `이어하기` 로 표시되고 같은 `quickLoadRuntime()` payload 를 복원한다. `tools/verify_title_start_browser.py` 와 `tools/verify_web_assets.py` 는 제목 `이어하기` 와 맵 화면 `임시 불러오기` 라벨을 함께 확인한다. 이 변경은 플레이 UI 정리이며 원본 save event proof 로 승격하지 않는다.

- 2026-06-04 제목 화면 전투 탐색 시작/이어하기 개선: 제목 Canvas 메뉴에 `전투 탐색 시작` 을 추가해, 쿼리나 도구 패널 없이도 새 게임을 필드 전투 탐색 모드로 바로 시작할 수 있게 했다. 이 경로는 `map1_02b@11,12` 로 시작한 뒤 `fieldEncounter.enabled=True`, HUD `전투 0/6`, URL `encounter=1`, 임시 저장 payload 의 `fieldEncounter.source=prototype-field-encounter` 를 남긴다. 필드 전투 탐색을 켜거나 끄는 순간도 `field-encounter-enable`/`field-encounter-disable` 로 자동 저장해 모드 자체가 이어하기에 남는다. 제목 메뉴의 `이어하기` 행은 저장 payload 를 읽어 `이어하기 map1_02b 11,12` 또는 `이어하기 map1_02b 11,12 전투` 처럼 위치/모드를 표시하고, 긴 라벨은 Canvas 메뉴 폭에 맞춰 줄인다. 필드 전투 탐색이 켜진 상태에서 threshold 이전 실제 `ArrowRight` 이동 입력으로 한 칸 이동을 완료하면 `field-encounter-step` 으로 자동 저장해 이동 후 좌표, `fieldEncounter.stepCount=1`, HUD `전투 1/6` 을 보존한다. `tools/verify_title_start_browser.py` 는 제목 메뉴 row pointer 선택, HUD/URL, mode `field-encounter-enable` autosave 와 이동 입력 기반 1걸음 `field-encounter-step` autosave payload 를 확인하고, 다시 제목 화면으로 돌아와 `이어하기` 를 눌렀을 때 이동 후 좌표에서 `encounter=1`, HUD `전투 1/6`, 메뉴 라벨 `전투 탐색 끄기 1/6` 이 복원되는지도 확인한다. 이어서 런타임 메뉴의 `전투 탐색 끄기 1/6` 을 실행해 `field-encounter-disable` autosave 가 만들어지고, 같은 이동 후 좌표의 제목 `이어하기` 복원 뒤에는 URL 에 `encounter=1` 이 빠지고 HUD 에 전투 탐색 카운터가 사라지는지도 확인한다. 이 변경은 걷기 -> 필드 전투 -> 보상/드롭 -> 임시 저장/이어하기로 이어지는 웹 플레이 루프 접근성 개선이며, 원본 encounter table/runtime proof 로 승격하지 않는다.

- 2026-06-04 제목 화면 후보 진행 노출 개선: 기본 제목 Canvas 메뉴에도 `후보 진행` 을 표시해, 도구 패널을 열지 않아도 확인된 시작점 `map1_02b@11,12` 에서 후보 routeAssist 진행 모드로 바로 들어갈 수 있게 했다. `tools/verify_title_start_browser.py` 는 초기 제목 메뉴가 `처음부터`, `전투 탐색 시작`, `후보 진행` 을 포함하고, 제목 메뉴 row pointer 로 `후보 진행` 을 선택하면 `trialTransitions=routeAssist`, `routeGoal=map2_02d`, `routePathValue=map2_02d`, `routeNextText=다음` 상태가 되는지 확인한다. 이 변경은 후보 진행을 실제 플레이 선택지로 노출하는 UX 개선이며, `map1_01a -> map2_02d` 원본 route promotion proof 로 승격하지 않는다.

- 2026-06-04 제목 화면 savedat 파일 접근 개선: 기본 제목 Canvas 메뉴에 `세이브 파일` 을 추가해, 상단 도구 패널을 열지 않아도 원본 `savedat*.dat`/zip 파일 선택을 시작할 수 있게 했다. 이 항목은 기존 `loadSavedatFile()` 파서와 hidden `saveFileInput` 경로를 그대로 쓰며, `tools/verify_title_start_browser.py` 는 제목 메뉴 row pointer 선택이 `requestSavedatFile("title-menu")` 을 호출하고 input accept 가 `.dat,.zip` 을 포함하는지 확인한다. 이 변경은 실제 저장 데이터 시작 경로를 첫 화면으로 옮긴 UX 개선이며, real selector `2:0` captured save 나 `map1_01a -> map2_02d` route promotion proof 를 새로 만든 것은 아니다.

- 2026-06-04 제목 화면 세이브 슬롯 스캔 개선: 기본 제목 Canvas 메뉴에 `세이브 슬롯` 을 추가해, 도구 패널의 scan 항목이나 `savedatScan=1` URL 없이도 로컬 `SAVEDATA/savedat1-9.dat|zip` 및 `SaveData/savedat1-9.dat|zip` 슬롯 검사를 바로 실행할 수 있게 했다. 현재 repo 슬롯 디렉터리에는 README 외 캡처 save 가 없으므로 smoke 는 `?savedatScan=1`, `HWANSE_LAST_TITLE_SAVEDAT_SCAN source=title-menu`, `foundCount=0`, `loaded=False`, 제목 menu notice `SAVEDATA/savedat1-9 dat/zip not found; also checked SaveData` 를 확인한다. 실제 슬롯을 넣으면 기존 `loadScannedSavedat()` 이 real route proof 후보를 우선 선택하고 `openSavedatSummary()` 로 로드한다. 이 변경은 캡처 save 투입 후 첫 화면 진입성을 높이는 UX 개선이며, 현 상태의 `foundCount=0` 은 route promotion proof 가 아니라 blocked 상태 유지 근거다.

- 2026-06-04 제목 화면 샘플 세이브 시작/이어하기 개선: 기본 제목 Canvas 메뉴에 `샘플 세이브` 를 추가해, 도구 패널의 public savedat select 나 URL query 를 몰라도 공개 savedat 샘플 목록을 고를 수 있게 했다. 제목 샘플 하위 메뉴는 `Debug savedat2 0:0`, `Release savedat2 0:0`, `Flack3r savedat2 1:0`, `Debug savedat1 22:0`, `Debug savedat1 copy`, `뒤로` 를 표시하고, smoke 는 `Flack3r savedat2 1:0` 행을 선택해 HUD 기준 `map2_02d@5,14` 에서 플레이를 시작하는지 확인한다. 이 항목은 기존 `publicSave=flack3r-savedat2`/`loadPublicSavedatSample()`/`openSavedatSummary()` 경로를 재사용하고, URL query 를 `?publicSave=flack3r-savedat2&map=map2_02d&startTile=5%2C14` 로 맞추며, savedat 원본 좌표 후보 `5,15`, runtime state money `983062`, item `herb:3`, party `Ataho/Rinshan/Smashu`, selector `1:0` 을 로드한다. 이 상태를 임시 저장하면 title `이어하기` 행은 `이어하기 map2_02d 5,14 세이브 1:0` 로 표시되고, 타이틀에서 이어가도 loadedSaveSummary selector `1:0`, runtime money/items/party, HUD, URL `?map=map2_02d&startTile=5%2C14` 가 복원된다. `tools/verify_title_start_browser.py` 는 제목 메뉴 row pointer 선택, 샘플 하위 메뉴 key `sampleSavedat:flack3r-savedat2`, `HWANSE_LAST_TITLE_PUBLIC_SAVEDAT source=title-menu`, loaded map/selector/runtime state/HUD, quick-save loadedSaveSummary payload, title continue restore 를 확인한다. 이 변경은 파일 없이 즉시 savedat 기반 플레이를 시작하고 재개하는 UX 개선이며, 이 공개 샘플은 current selector `2:0`/selected pointer `0x00540714` 를 덮지 않으므로 `map1_01a -> map2_02d` route promotion proof 로 승격하지 않는다.

- 2026-06-04 제목 화면 후보 목표 선택/이어하기 개선: 기본 제목 Canvas 메뉴에 `후보 목표` 하위 메뉴를 추가해, 인게임 메뉴나 상단 route select 를 열지 않아도 타이틀에서 후보 경로 목표를 직접 고를 수 있게 했다. 목록은 `map2_18d 0/3` 처럼 목표 맵과 진행도를 표시하고, smoke 는 `후보 목표 -> map2_18d` 선택이 확인된 시작점 `map1_02b@11,12` 로 진입한 뒤 `trialTransitions=routeAssist&routeGoal=map2_18d`, route path value `map2_18d`, HUD `후보 map2_18d  다음 map1_01a` 를 노출하는지 확인한다. 이 상태를 임시 저장하면 제목 `이어하기` 행은 `이어하기 map1_02b 11,12 후보 map2_18d` 로 표시되고, 타이틀에서 이어가도 같은 route goal, URL query, HUD route line 이 복원된다. 긴 후보 목록은 타이틀 메뉴 window 로 화면 안에 렌더링된다. 이 변경은 후보 진행을 첫 화면에서 더 직접 플레이하고 재개하게 하는 UX 개선이며, 여전히 `map1_01a -> map2_02d` 원본 strict hotspot/selected-root 실행 proof 로 승격하지 않는다.

- 2026-06-04 제목 화면 장거리 후보 목표 선택/이어하기 검증 보강: `tools/verify_title_start_browser.py` 는 타이틀 `후보 목표` 하위 메뉴에서 첫 8개 visible row 밖의 `map5_40f` 까지 window 를 이동해 직접 선택할 수 있는지 확인한다. 선택 뒤에는 `map1_02b@11,12` 에서 `trialTransitions=routeAssist&routeGoal=map5_40f`, route path value `map5_40f`, HUD `후보 map5_40f  다음 map1_01a` 를 노출하고, 임시 저장 payload 의 `routeState.selectedRouteGoal=map5_40f` 및 제목 `이어하기 map1_02b 11,12 후보 map5_40f` 복원을 확인한다. `tools/verify_web_assets.py` 는 `targetIndex >= 8`, visible window 내부 클릭, quick save/continue 복원을 함께 검증한다. 이 보강은 후보 25개 목표가 첫 화면에서 실사용 가능하다는 UX/routeAssist coverage 이며, 원본 route promotion proof 나 completion gate 통과로 승격하지 않는다.

- 2026-06-04 `map5_40f` 장거리 후보 진행/이어하기 검증 보강: `tools/verify_candidate_deep_route_browser.py` 를 추가해 `map1_02b@11,12` 에서 `routeGoal=map5_40f` 로 시작한 뒤 실제 `activateNextRoutePath()` 흐름을 25번 반복해 `map1_02b -> map1_01a -> map2_02d -> map2_09g -> map2_11g -> map2_17h -> map2_15j -> map5_09h -> map5_07h -> map5_05h -> map5_03h -> map5_04h -> map5_02h -> map5_40f` 전체 후보 경로를 따라간다. 각 후보 edge 는 `routeAutoSave` 로 진행 기록을 저장하고, 최종 `map5_40f@65,39` 에서 `routeGoal=map5_40f`, `routePathValue=map5_40f`, `routeNextText=완료`, `routeCandidateCount=12`, `savedRouteCandidateCount=12`, `pathProgress=후보 완료 12/12` 를 확인한다. 제목 화면 `이어하기 map5_40f 65,39 후보 map5_40f` 복원 뒤에도 같은 route goal/진행 카운트가 유지된다. 이 검증은 사용자가 후보 경로를 장거리 목표까지 실제로 진행하고 재개할 수 있음을 확인하는 웹 gameplay 보강이며, 후보 routeAssist edge 를 원본 정상 route proof 로 승격하지 않는다.

- 2026-06-04 후보 오브젝트 정면 조사 하이라이트: 키보드/패드 A/Enter 조사가 발밑 후보 없이 바라보는 앞 타일 후보를 잡을 때, `HWANSE_LAST_ACTION_PROMPT.target` 이 선택 asset/anchor 를 기록하고 일반 맵 렌더가 해당 스프라이트에 action highlight 를 그린다. `out/candidate_event_object_browser_smoke.*` 는 `map2_03l` 아래 타일에서 위를 보고 누르는 정면 action 이 `event-object-candidates:map2_03l scope=facing-object prompt=Enter -> 조사 zg_kni 3개 actionHighlight=zg_kni assets=zg_kni,zm_2,zs_rg` 를 남기고, prompt snapshot 의 target 이 `zg_kni@11,11`, promptRender 의 `actionHighlightedCount=1`/`actionAssetKey=zg_kni` 인지 확인한다. 이 변경도 원본 NPC/object script 실행 proof 로 승격하지 않고 `achieved=False` 를 유지한다.

- 2026-06-04 후보 전투 title 이어하기 복원 개선: `tools/verify_candidate_battle_browser.py` 는 `map1_02b` 일반 후보 전투 승리 후 quick save 된 완료/보상 상태가 제목 화면 `이어하기 map1_02b 11,12` 에서도 복원되는지 확인한다. 복원 뒤에는 `전투 완료 btl_b1`, source prompt `Enter -> 전투 완료 btl_b1`, 완료 알림 `battle-complete:event-dialogue-block-015`, 런타임 메뉴 `전투 완료 btl_b1`, `battleVictoryCount=1`, `dropCount=2`, `expTotal=3`, `levelAfter=2`, `nextExp=3/125`, 상단 `임시 불러오기` 라벨이 유지된다. 이 변경은 전투 완료/보상 상태를 첫 화면에서 이어갈 수 있게 하는 browser-local 저장 UX 검증이며 원본 event-driven battle/story flag proof 로 승격하지 않는다.
- 2026-06-05 후보 전투 완료 결과/목표 실행 보강: 완료된 후보 전투를 다시 실행하려 할 때 열리는 `battle-complete:event-dialogue-block-015` 완료 알림과 `prototype-progress:map1_02b` 진행 기록 리뷰에 전투 보상 요약을 함께 표시하게 했다. 일반 후보 전투 승리/복원 smoke 는 이제 완료 알림과 진행 리뷰가 `전투 보상 소지금 75 / 경험치 +7`, `전투 드롭 약초 2`, `전투 레벨 Ataho Lv2 3/125` 를 포함하는지 확인한다. 또한 완료된 전투가 있는 맵의 현재 목표는 `후보 전투 완료 btl_b1` / `완료 알림 확인` 으로 바뀌고, `목표` 실행도 `objectiveAction=battle-completion-notice`, `objectiveActiveId=battle-complete:event-dialogue-block-015` 로 같은 완료 알림을 연다. 이 보강은 전투 승리 뒤 보상/성장 결과가 로그에만 묻히지 않고 완료 상태 UI와 진행 리뷰에서 바로 보이며, 현재 목표 버튼으로도 확인할 수 있게 하는 웹 gameplay UX 개선이다. 원본 reward table, enemy row, combat formula, event-driven battle/story flag runtime proof 로 승격하지 않는다.
- 2026-06-05 상태/기술 메뉴 진행 목표/이어하기 보강: 새 게임에서 `상태 1` 또는 `기술 0` 메뉴를 확인하면 각각 `status-menu-prototype`/`skill-menu-prototype` 진행 기록을 남기고 `autoSource=status-menu-prototype|skill-menu-prototype` 으로 자동 저장한다. 이후 현재 목표는 `후보 상태 완료 map1_02b` 또는 `후보 기술 완료 map1_02b` / `완료 알림 확인` 으로 바뀌며, `목표` 실행은 `menu-review-completion-notice` 로 `status-review-complete:map1_02b` 또는 `skill-review-complete:map1_02b` 완료 알림을 연다. `tools/verify_candidate_status_menu_browser.py` 와 `tools/verify_candidate_skill_menu_browser.py` 는 이 상태가 제목 화면 `이어하기 map1_02b 11,12` 에서도 `quickLoadText=임시 불러오기`, `statusProgressCount=1`/`skillProgressCount=1`, 같은 완료 목표와 activeId 로 복원되는지 확인한다. 이 보강은 메뉴 확인도 저장/재개되는 실제 웹 gameplay 루프로 끌어올리는 UX 개선이며, savedat 장비 offset, 원본 상태 flag, 원본 skill/story flag runtime proof 로 승격하지 않는다.
- 2026-06-07 상태/기술 메뉴 확인 feedback 보강: `startStatusMenuReview()` 와 `startSkillMenuReview()` 는 이제 메뉴 확인 진행 기록을 남길 때 `menu-review-feedback` overlay 도 함께 만들고 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 기록한다. 상태 메뉴는 `statusFeedback=status-menu-review-feedback:status-menu-prototype:status-menu:map1_02b:상태 확인 1명`, `statusFeedbackRender=True`, `statusSound=menuConfirm`, `statusSoundSrc=../extract_wlk/04.wav`, `statusSoundPlayed=True` 를 남기고, 기술 메뉴는 `skillFeedback=skill-menu-review-feedback:skill-menu-prototype:skill-menu:map1_02b:기술 확인 0/0` 과 같은 sound marker 를 남긴다. 이 보강은 상태/기술 확인도 대화창/자동 저장뿐 아니라 즉시 보이는 화면 피드백과 확인 효과음을 갖게 하는 웹 gameplay UX 개선이며, 원본 savedat status/skill byte runtime, 장비 offset, story flag proof 로 승격하지 않는다.
- 2026-06-07 상태/기술 완료 알림 feedback 보강: `menu-review-completion-notice` 로 열린 완료 알림도 `menu-review-feedback` overlay 와 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 기록한다. 상태 완료는 `statusNoticeFeedback=status-menu-completion-notice-feedback:상태 확인 완료 1/1`, `statusNoticeFeedbackRender=True`, `statusNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 남기고, 기술 완료는 `skillNoticeFeedback=skill-menu-completion-notice-feedback:기술 확인 완료 1/1`, `skillNoticeFeedbackRender=True`, `skillNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 남긴다. `tools/verify_candidate_status_menu_browser.py` 와 `tools/verify_candidate_skill_menu_browser.py` 는 savedat 메뉴, 새 게임 메뉴, 제목 이어하기 복원 경로에서 같은 marker 를 확인한다. 이 보강은 메뉴 확인 완료 목표가 대화 텍스트뿐 아니라 화면/효과음 피드백까지 갖게 하는 웹 gameplay UX 개선이며, 원본 savedat status/skill byte runtime, 장비 offset, story flag proof 로 승격하지 않는다.
- 2026-06-05 전투 턴 완료 목표/이어하기 보강: `battle-turn-prototype` 으로 저장된 전투 턴 결과도 `battleTurnPrototypeCompletionState()` 에서 완료 상태로 요약하고, 현재 목표가 `후보 전투 턴 완료 btl_n2` / `완료 알림 확인` 으로 바뀌게 했다. 제목 화면 `이어하기 map2_07e 11,11` 로 독 상태가 저장된 턴을 복원한 뒤 `목표` 실행은 `battle-turn-completion-notice` 로 `battle-turn-complete:map2_07e` 완료 알림을 열며, 알림에는 `전투 턴 완료 1/1`, `btl_n2`, `독액`, `상태 독`, Ataho HP 변화가 표시된다. `tools/verify_candidate_battle_browser.py` 는 이 복원/목표 실행 경로와 `battleVictoryCount=0` 유지, `originalEnemyAiImplemented=False`, `originalStatusFormulaImplemented=False`, `originalCombatFormulaImplemented=False`, `originalStoryFlagRuntimeImplemented=False` 를 확인한다. 이 보강은 전투 중 한 턴 결과도 저장/재개 후 현재 목표에서 재확인하는 웹 gameplay UX 개선이며, 원본 적 AI/상태 공식/전투 공식/story flag proof 로 승격하지 않는다.
- 2026-06-07 전투 턴 완료 알림 feedback 보강: `battle-turn-completion-notice` 로 열린 완료 알림도 `battle-turn-completion-notice-feedback` overlay 와 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 기록한다. `tools/verify_candidate_battle_browser.py` 는 `map2_07e` title continue 복원 뒤 목표 실행에서 `turnNoticeFeedback=battle-turn-completion-notice-feedback:전투 턴 완료 1/1`, `turnNoticeFeedbackRender=True`, `turnNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 확인한다. 이는 전투 턴 완료 목표가 대화 텍스트뿐 아니라 플레이 화면/효과음 피드백도 갖게 하는 웹 gameplay UX 보강이며, 원본 적 AI/상태 공식/전투 공식/DirectSound timing/story flag proof 로 승격하지 않는다.
- 2026-06-05 전투 상태 효과 턴 보강: 전투 턴 시작 시 `poison` 은 prototype 독 피해를 적용하고, `paralysis` 는 prototype 행동 불가 상태로 해당 행동을 건너뛰게 했다. `event-dialogue-block-038:btl_n2` 의 두 번째 턴 smoke 는 Ataho 가 첫 반격 뒤 `poison` 상태와 HP 28 을 유지하다가 다음 행동 시작에 `battle-status-effect-prototype` / `prototype-battle-status-effect` 로 `poisonDamage=3`, `poisonHp=28->25` 를 기록하고, 화면 피드백도 `statusFeedbackSources=enemy-status-apply:poison,battle-status-poison-damage:poison`, `statusFeedbackTexts=독,독 -3`, `statusFeedbackRender=True`, `statusFeedbackDuration=760` 으로 렌더되는지 확인한다. 이어진 적 반격 자동 저장은 `battle-turn-prototype`, `turnHp=25->17`, `statusEffectDamage=3`, `battleStatusCount=1`, `battleTurnCount=2`, `savedHp=17`, `savedPoison=True` 를 보존한다. 이는 웹 전투에서 상태이상이 실제 턴 결과와 화면 피드백을 모두 바꾸게 하는 gameplay 보강이며, 원본 상태 공식/전투 공식/적 AI/story flag proof 로 승격하지 않고 `originalStatusFormulaImplemented=False`, `originalCombatFormulaImplemented=False` 를 유지한다.
- 2026-06-05 전투 마비 행동 불가 검증 보강: `event-dialogue-block-041:btl_a1` 의 `boss_2` prototype profile 은 `status=마비` 를 부여하고, 다음 Ataho 턴은 `battle-status-effect-prototype` 으로 `effectKind=paralysis`, `skipped=True` 를 기록한다. 이때 Ataho 명령은 실행되지 않아 적 HP 가 `90->90` 으로 유지되고, 화면 피드백은 `statusFeedbackSources=enemy-status-apply:paralysis,battle-status-skip-turn:paralysis`, `statusFeedbackTexts=마비,마비 행동불가`, `statusFeedbackRender=True`, `statusFeedbackDuration=760` 으로 표시된다. 적 반격만 이어져 `battle-turn-prototype` payload 에 `commandKey=status:skip-turn`, `statusEffectSkipped=True`, `turnHp=27->18`, `battleStatusCount=1`, `battleTurnCount=2`, `savedHp=18`, `savedParalysis=True` 가 저장된다. 이는 prototype 마비 상태가 실제 전투 턴을 건너뛰고 플레이어에게 즉시 보이는 gameplay 검증이며, 원본 상태 공식/전투 공식/적 AI/story flag proof 로 승격하지 않는다.
- 2026-06-07 전투 상태이상 WLK sound marker 보강: `recordBattleStatusFeedback()` 은 이제 전투 중 poison 턴 피해 feedback 에 `battleHit` WLK 사운드(`../extract_wlk/09.wav`)를, paralysis 행동 불가 feedback 에 `menuMove` WLK 사운드(`../extract_wlk/03.wav`)를 연결하고 feedback/render snapshot 에 `battleStatusSound`, `battleStatusSoundSrc`, `battleStatusSoundPlayed` 를 남긴다. 상태 부여 자체(`독`, `마비`)는 같은 적 공격의 hit sound 와 겹치므로 별도 사운드를 만들지 않는다. `tools/verify_candidate_battle_browser.py` 는 8013 기준 `statusEffectTurn` 에서 `statusFeedbackSound=battle-status-poison-damage:battleHit:../extract_wlk/09.wav:True`, `paralysisTurn` 에서 `statusFeedbackSound=battle-status-skip-turn:menuMove:../extract_wlk/03.wav:True` 를 확인한다. 이는 전투 안 상태이상 효과가 화면/저장뿐 아니라 WLK 효과음 provenance 도 갖게 하는 웹 gameplay UX 보강이며, 원본 상태 공식/DirectSound timing/story flag proof 로 승격하지 않는다.
- 2026-06-05 전투 도구 화면 피드백 보강: 전투 중 도구 사용 성공 경로가 `HWANSE_BATTLE_ITEM_FEEDBACK_LOG`/`HWANSE_BATTLE_ITEM_FEEDBACK_RENDER` 를 남기고, HP/MP 회복, 상태 회복, 부활 결과를 캔버스 위에 짧게 표시한다. `event-dialogue-block-038:btl_n2` status-cure smoke 는 `해독초` 사용 뒤 `itemFeedback=battle-item-use:item_2:독 회복`, `itemFeedbackRender=True`, `itemFeedbackDuration=900` 과 snapshot 의 `browserBattleItemFeedbackImplemented=True` 를 확인한다. WebKit savedat 전투 도구 smoke 도 `약초` HP 회복 `itemFeedback=battle-item-use:herb:HP +20`, `마법의 물약` MP 회복 `menuItemFeedback=battle-item-use:mp_recovery:MP +50`, `해독초` 상태 회복 `statusItemFeedback=battle-item-use:item_2:독 회복`, `마수석` 부활 `reviveItemFeedback=battle-item-use:item_6:부활` 이 모두 `*FeedbackRender=True` 로 렌더되는지 확인한다. 이는 전투 도구 효과가 battle log 에만 남지 않고 즉시 보이는 gameplay UX 보강이며, 원본 item formula/status flag/story flag proof 로 승격하지 않는다.
- 2026-06-07 전투 도구 WLK sound feedback marker 보강: 성공한 `useBattleItem()` 경로는 이제 `recordBattleItemFeedback()` 안에서 `item` WLK 사운드(`../extract_wlk/11.wav`)를 재생하고 feedback/render snapshot 에 `battleItemSound=item`, `battleItemSoundSrc=../extract_wlk/11.wav`, `battleItemSoundPlayed=True` 를 남긴다. `tools/verify_mobile_browser_controls.py` 는 8013 기준 savedat 전투 도구 smoke 에서 `itemFeedbackSound=item:../extract_wlk/11.wav:True`, `menuItemFeedbackSound=item:../extract_wlk/11.wav:True`, `statusItemFeedbackSound=item:../extract_wlk/11.wav:True`, `reviveItemFeedbackSound=item:../extract_wlk/11.wav:True` 를 확인한다. 이는 전투 도구 성공 조작이 화면 overlay, 자동 저장, WLK 효과음 provenance 를 같은 피드백 entry 안에 남기도록 한 웹 gameplay UX 보강이며, 원본 item formula/DirectSound timing/story flag proof 로 승격하지 않는다.
- 2026-06-06 전투 도구 실패 화면 피드백 보강: 전투 중 HP/상태 회복 대상이 없어 도구 사용이 실패할 때도 `battle-item-failed-feedback` overlay 를 남긴다. `tools/verify_candidate_battle_browser.py` 는 `event-dialogue-block-038:btl_n2` 에서 full-HP Ataho 가 `약초 x1` 을 선택하면 `hpFailFeedback=battle-item-failed-feedback:herb:약초 대상 없음`, `hpFailFeedbackRender=True`, `hpFailSoundItemCount=None` 이 표시되고, 약초 수량이 1개로 유지되며 `item-use-prototype` 진행 기록이나 도구 자동 저장을 만들지 않는지 확인한다. 이어 독이 걸리기 전 Ataho 가 `해독초 x1` 을 선택하면 `itemFailFeedback=battle-item-failed-feedback:item_2:해독초 회복 대상 없음`, `itemFailFeedbackRender=True`, `itemFailSoundItemCount=None` 이 표시되고, 해독초 수량이 1개로 유지되며 `item-use-prototype` 진행 기록이나 도구 자동 저장을 만들지 않는지 확인한다. 이후 같은 전투에서 `독액` 반격으로 poison 이 걸린 뒤 기존 성공 사용 경로는 계속 `itemFeedback=battle-item-use:item_2:독 회복`, `itemFeedbackRender=True`, `itemFeedbackDuration=900` 으로 검증한다. 이 변경은 전투 도구 실패 조작도 battle log 에만 묻히지 않고 플레이 화면에서 즉시 이해되게 하는 웹 gameplay UX 보강이며, 원본 item formula/status flag/story flag proof 로 승격하지 않는다.
- 2026-06-05 맵 메뉴 도구 화면 피드백 보강: 맵 메뉴의 `useInventoryItem()` 성공 경로도 `HWANSE_INVENTORY_ITEM_FEEDBACK_LOG`/`HWANSE_INVENTORY_ITEM_FEEDBACK_RENDER` 를 남기고, HP/MP 회복, 상태 회복, 부활 결과를 메뉴 화면 위에 짧게 표시한다. `tools/verify_title_start_browser.py` 는 새 게임 약초 사용에서 `itemFeedback=inventory-item-use:herb:약초 HP +12`, `itemFeedbackRender=True`, `durationMs=1100`, `browserInventoryItemFeedbackImplemented=True` 를 확인한다. `tools/verify_mobile_browser_controls.py` 는 public savedat 맵 메뉴 약초 사용에서 `inventoryFeedback=inventory-item-use:herb:약초 HP +30`, `inventoryFeedbackRender=True`, `countBefore=3`, `countAfter=2` 를 확인한다. 이는 맵 메뉴 도구 효과가 menuNotice/저장 기록에만 묻히지 않고 즉시 보이는 gameplay UX 보강이며, 원본 item formula/status flag/story flag proof 로 승격하지 않는다.
- 2026-06-06 맵 메뉴 도구 실패 화면 피드백: `useInventoryItem()` 은 HP/MP/상태 회복 대상이 없어 도구 사용이 실패할 때도 `inventory-item-failed-feedback` overlay 를 남긴다. `tools/verify_title_start_browser.py` 는 새 게임 no-loaded-savedat 상태에서 Ataho HP 가 이미 가득 찬 채 `약초 x1` 을 선택하면 `itemFailFeedback=inventory-item-failed-feedback:herb:약초 대상 없음`, `itemFailFeedbackRender=True` 가 표시되고, HP/약초 수량이 그대로이며 `item-use-prototype` 진행 기록, autosave, item WLK sound 를 만들지 않는지 확인한다. 이어 상태이상이 없는 Ataho 가 `해독초 x1` 을 선택하면 `statusFailFeedback=inventory-item-failed-feedback:item_2:해독초 회복 대상 없음`, `statusFailFeedbackRender=True` 가 표시되고, HP/status/해독초 수량이 그대로이며 진행 기록, autosave, item WLK sound 를 만들지 않는지 확인한다. 이어 HP 를 24로 낮춘 기존 성공 사용 경로는 계속 `itemFeedback=inventory-item-use:herb:약초 HP +12`, `itemFeedbackRender=True`, `itemSoundItemCount=1` 로 검증한다. 이 변경은 실패 도구 조작도 플레이 화면에서 즉시 이해되게 하는 웹 gameplay UX 보강이며 원본 item formula/status flag/story flag proof 로 승격하지 않는다.
- 2026-06-06 맵 메뉴 도구 WLK item sound 보강: `useInventoryItem()` 성공 경로도 전투 도구/장비/상점과 같은 추출 WLK `item` 효과음 `extract_wlk/11.wav` 를 요청한다. `tools/verify_title_start_browser.py` 는 새 게임 약초 사용 직전 사운드 로그를 초기화한 뒤 `itemSoundItemCount=1` 과 `/extract_wlk/11.wav` 를 확인한다. 이 변경은 맵 메뉴 도구 사용의 웹 gameplay 피드백 강화이며 원본 DirectSound mixing/타이밍 완전 재현 증거는 아니다.
- 2026-06-07 맵 메뉴 도구 WLK sound feedback marker 보강: 성공한 `useInventoryItem()` 경로는 이제 `recordInventoryItemFeedback()` 안에서 `item` WLK 사운드(`../extract_wlk/11.wav`)를 재생하고 feedback/render snapshot 에 `inventoryItemSound=item`, `inventoryItemSoundSrc=../extract_wlk/11.wav`, `inventoryItemSoundPlayed=True` 를 남긴다. 실패 도구 피드백은 계속 사운드/진행/자동 저장을 만들지 않는다. `tools/verify_title_start_browser.py` 는 새 게임 약초 사용의 `itemFeedbackSound=item`/`itemFeedbackSoundSrc=../extract_wlk/11.wav`/`itemFeedbackSoundPlayed=True` 를 확인하고, `tools/verify_mobile_browser_controls.py` 는 public savedat 맵 메뉴 약초 사용에서 `inventoryFeedbackSound=item:../extract_wlk/11.wav:True` 를 요구한다. 이는 맵 메뉴 도구 조작이 화면 overlay, 저장 기록, WLK 효과음 provenance 를 같은 피드백 entry 안에 남기도록 한 웹 gameplay UX 보강이며, 원본 item formula/DirectSound timing/story flag proof 로 승격하지 않는다.
- 2026-06-05 전투 기술 화면 피드백 보강: 성공한 전투 skill command 는 이제 `HWANSE_BATTLE_SKILL_FEEDBACK_LOG`/`HWANSE_BATTLE_SKILL_FEEDBACK_RENDER` 를 남기고, 기술명/피해/MP 소비를 캔버스 위에 짧게 표시한다. `tools/verify_mobile_browser_controls.py` 의 public savedat 전투는 Ataho `돌려차기` 사용 직후 `skillFeedback=battle-skill-use:Ataho:돌려차기:돌려차기 -112 / MP -2`, `skillFeedbackRender=True`, `durationMs=900`, `browserBattleSkillFeedbackImplemented=True` 를 확인하고, snapshot 이 `mpBefore=999`, `mpAfter=997`, `enemyHpBefore=700`, `enemyHpAfter=588`, `damage=112` 를 보존하는지 검증한다. MP 부족 가드도 적 HP/source row/턴을 바꾸지 않으면서 `noMPFeedback=battle-skill-no-mp:Ataho:돌려차기:돌려차기 MP 부족`, `noMPFeedbackRender=True`, `failed=True`, `insufficientMp=True`, `damage=0` 을 표시한다. 이는 전투 기술 결과가 battle log/자동 저장에만 묻히지 않고 즉시 보이는 gameplay UX 보강이며, 원본 skill formula/combat formula/story flag proof 로 승격하지 않는다.
- 2026-06-07 전투 기술 WLK sound feedback marker 보강: 성공한 전투 skill command 는 기존 enemy hit 효과음 `battleHit`(`../extract_wlk/09.wav`)을 `recordBattleSkillFeedback()` entry 에 연결해 `battleSkillSound=battleHit`, `battleSkillSoundSrc=../extract_wlk/09.wav`, `battleSkillSoundPlayed=True` 를 log/render snapshot 모두에 남긴다. MP 부족 가드는 기존 `menuConfirm` WLK(`../extract_wlk/04.wav`)를 같은 feedback entry 에 연결한다. `tools/verify_mobile_browser_controls.py` 는 public savedat 전투에서 `skillFeedbackSound=battleHit:../extract_wlk/09.wav:True` 와 `noMPFeedbackSound=menuConfirm:../extract_wlk/04.wav:True` 를 확인하고, `tools/verify_web_assets.py` 는 smoke JSON/MD와 completion audit evidence 에서 같은 marker 를 요구한다. 이는 전투 기술 성공/실패가 battle log, 화면 overlay, WLK 효과음을 같은 gameplay feedback 단위로 남기게 하는 웹 구현 보강이며, 원본 skill formula/DirectSound timing/story flag proof 로 승격하지 않는다.
- 2026-06-05 전투 기술 완료 목표/이어하기 보강: public savedat 전투에서 Ataho `돌려차기` 가 `battle-skill-prototype` 진행 기록과 `scope=battle-skill` 자동 저장을 남기면 현재 목표가 `후보 전투 기술 완료 btl_a1` / `완료 알림 확인` 으로 바뀌게 했다. 이 상태에서 `목표` 실행은 `battle-skill-completion-notice` 로 `battle-skill-complete:map1_01a` 완료 알림을 열고, 알림에는 `전투 기술 완료 1/1`, `Ataho 돌려차기`, `MP 999->997`, `보스 후보 HP 700->588`, `피해 112` 가 표시된다. `tools/verify_mobile_browser_controls.py` 는 기술 사용 직후 objective/action/active id 와 완료 알림을 확인하고, 제목 화면 `이어하기 map1_01a 1,2` 로 복원한 뒤에도 `quickLoadText=임시 불러오기`, `skillTitleContinue=후보 전투 기술 완료 btl_a1/battle-skill-completion-notice/battle-skill-complete:map1_01a` 가 유지되는지 확인한다. 이 보강은 추출 기술 텍스트와 savedat skill byte 로 움직이는 웹 전투 행동을 저장/재개 후 현재 목표에서 재확인하는 gameplay UX 개선이며, 원본 skill formula/combat formula/story flag proof 로 승격하지 않는다.
- 2026-06-08 전투 기술 완료 알림 feedback 보강: `battle-skill-completion-notice` 로 열린 완료 알림도 `recordBattleSkillFeedback()` entry 를 남겨 `skillNoticeFeedback=battle-skill-completion-notice-feedback:전투 기술 완료 1/1`, `skillNoticeFeedbackRender=True`, `skillNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 검증한다. 같은 entry 는 `Ataho 돌려차기`, `MP 999->997`, `보스 후보 HP 700->588`, `피해 112` 를 보존하고 `tools/verify_mobile_browser_controls.py` 와 `tools/verify_web_assets.py` 가 8013 기준 public savedat 전투에서 확인한다. 이는 전투 기술 완료 목표가 대화 텍스트뿐 아니라 화면 overlay/WLK 확인음까지 갖게 하는 웹 gameplay UX 보강이며, 원본 skill formula/combat formula/story flag proof 로 승격하지 않는다.
- 2026-06-05 전투 도구 완료 목표 보강: public savedat 전투에서 Ataho `약초` 가 `item-use-prototype` 진행 기록과 `scope=battle-item` 자동 저장을 남기면 현재 목표가 `후보 전투 도구 완료 btl_a1` / `완료 알림 확인` 으로 바뀌게 했다. 이 상태에서 `목표` 실행은 `battle-item-completion-notice` 로 `battle-item-complete:map1_01a` 완료 알림을 열고, 알림에는 `전투 도구 완료 1/1`, `Ataho 약초`, `약초 3->2`, `Ataho HP 979->999` 가 표시된다. 같은 `약초` 완료 목표는 타이틀 `이어하기 map1_01a 1,2` 뒤에도 `itemTitleContinue=후보 전투 도구 완료 btl_a1/battle-item-completion-notice/battle-item-complete:map1_01a` 로 복원된다. 같은 전투 도구 서브메뉴 경로에서 `마법의 물약` 을 선택한 경우도 같은 완료 목표를 열고, 알림에는 `Rinshan 마법의 물약`, `마법의 물약 1->0`, `Rinshan MP 939->989` 가 표시된다. 상태 회복/부활 도구도 같은 완료 UX에 포함되어 `해독초` 는 `Smashu 해독초`, `해독초 1->0`, `상태 poison->정상` 을, `마수석` 은 `Ataho 마수석`, `마수석 1->0`, `Smashu HP 0->999`, `Smashu MP 0->999` 를 완료 알림에 남긴다. `tools/verify_mobile_browser_controls.py` 는 전투 도구 사용 직후 objective/action/active id 와 완료 알림을 확인하며, 별도 `battle-turn-prototype` 저장은 그 뒤 적 반격 HP/status 를 계속 보존한다. 이 보강은 전투 중 도구 사용 결과가 반격 턴 기록에 묻히지 않고 현재 목표에서 재확인되는 웹 gameplay UX 개선이며, 원본 item formula/status flag/story flag proof 로 승격하지 않는다.
- 2026-06-08 전투 도구 대상 선택 완료 알림 보강: `tools/verify_candidate_battle_browser.py` 는 수동 파티 전투에서 `도구 -> 약초 -> Rinshan` 대상 선택으로 HP 8->28, 약초 2->1 이 되는 경로도 완료 목표까지 확인한다. 대상 선택 직후 `objective=후보 전투 도구 완료 btl_b1`, `objectiveDetail=Ataho / 약초 / Rinshan / 2->1`, `objectiveAction=battle-item-completion-notice`, `objectiveActiveId=battle-item-complete:map1_02b` 를 열고, 전투 도구 완료 알림이 `battle-item-completion-notice-feedback:전투 도구 완료 1/1`, `itemTargetNoticeFeedbackRender=True`, `itemTargetNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 남기게 했다. 이는 전투 도구 대상 선택이 사용/저장/반격에서 끝나지 않고 완료 알림 overlay/WLK 확인까지 이어지는 웹 gameplay UX 보강이며, 원본 item formula/status flag/story flag proof 로 승격하지 않는다.

- 2026-06-05 후보 대사 완료 목표 실행 보강: `map4_08n` 의 직접 후보 대사 `event-dialogue-block-005,026` 을 모두 완료한 뒤 현재 목표가 `후보 대사 완료 map4_08n` / `완료 알림 확인` 으로 바뀌게 했다. 이 상태에서 `목표` 실행은 generic `prototype-progress` 리뷰로 빠지지 않고 `objectiveAction=dialogue-completion-notice`, `objectiveActiveId=dialogue-complete:map4_08n` 으로 같은 완료 알림을 연다. `tools/verify_candidate_dialogue_progress_browser.py` 는 완료 직후와 제목 화면 `이어하기 map4_08n 11,11` 복원 뒤 모두 이 목표 실행 경로를 확인한다. 이 보강은 완료된 대사 후보를 현재 플레이 목표에서 바로 재확인하는 웹 UX 개선이며, 원본 event VM/story flag runtime proof 로 승격하지 않는다.

- 2026-06-05 후보 조사 완료 목표 실행 보강: `map2_03l` 의 조사 후보 `event-object-candidates:map2_03l` 을 완료한 뒤 현재 목표가 `후보 조사 완료 map2_03l` / `완료 알림 확인` 으로 바뀌게 했다. 이 상태에서 `목표` 실행은 `objectiveAction=object-completion-notice`, `objectiveActiveId=event-object-complete:map2_03l` 로 완료 알림을 열고, 진행 기록 검토는 별도 `progressReview=prototype-progress:map2_03l` 로 계속 확인한다. `tools/verify_candidate_progress_browser.py` 는 첫 조사 시작은 상단 `목표` 버튼으로 열고, 저장/복원 뒤 완료 목표 실행과 진행 리뷰가 모두 유지되는지 확인한다. 이 보강은 완료된 조사 후보를 현재 목표에서 바로 재확인하는 웹 gameplay UX 개선이며, 원본 NPC/object script/story flag runtime proof 로 승격하지 않는다.
- 2026-06-07 후보 조사 완료 알림 overlay/WLK sound 보강: 완료된 오브젝트 조사 후보의 `목표` 완료 알림 경로가 완료 대화만 여는 데서 끝나지 않게 `event-object-completion-notice-feedback` overlay 를 맵 화면 위에 표시하고 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 남기게 했다. 일반 조사 실행 순간의 `event-object-inspect-feedback` 은 기존 source 를 유지하고, 복원 후 완료 알림 확인 조작만 별도 notice feedback 으로 구분한다. `tools/verify_candidate_progress_browser.py` 는 8013 기준 `prototype-progress:map2_03l` 복원 뒤 `objectiveAction=object-completion-notice` 경로에서 `objectNoticeFeedback=event-object-completion-notice-feedback:조사 완료 3`, `objectNoticeFeedbackRender=True`, `objectNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 요구하고, `tools/verify_web_assets.py`/`tools/summarize_completion_audit.py` 도 같은 marker 를 completion audit evidence 로 보존한다. 이는 완료된 조사 확인 조작을 실제 플레이 화면/효과음으로 보이게 하는 UX 보강이며, 원본 NPC/object script, event VM runtime, story flag proof 로 승격하지 않는다.

- 2026-06-05 후보 세이브 완료 목표 실행 보강: `map2_07e` current-map 세이브 후보를 완료한 뒤 현재 목표가 `후보 세이브 완료 map2_07e` / `완료 알림 확인` 으로 바뀌게 했다. 이 상태에서 `목표` 실행은 새 완료 알림 `save-point-complete:map2_07e` 를 열고, `objectiveAction=save-point-completion-notice`, `objectiveActiveId=save-point-complete:map2_07e` 를 남긴다. 기존 세이브 버튼/Enter 경로는 저장 포인트로 계속 사용할 수 있게 두고, 목표 실행은 저장 기록을 중복 증가시키지 않는 완료 확인으로 분리했다. `tools/verify_candidate_save_point_browser.py` 는 제목 화면 `이어하기 map2_07e 11,11` 복원과 직접 임시 불러오기 복원 양쪽에서 이 목표 실행 경로를 확인한다. 이 보강은 완료된 세이브 후보도 현재 목표에서 바로 재확인하는 웹 UX 개선이며, 원본 save point event/story flag runtime proof 로 승격하지 않는다.
- 2026-06-07 후보 세이브 완료 알림 overlay/WLK sound 보강: 완료된 save-point 후보의 title `이어하기`/직접 `임시 불러오기` 복원 뒤 `목표` 완료 알림 경로가 완료 대화만 여는 데서 끝나지 않게 `save-point-completion-notice-feedback` overlay 를 맵 화면 위에 표시하고 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 남기게 했다. 실제 세이브 실행 순간의 `save-point-feedback` 은 기존 source 를 유지하고, 복원 후 완료 알림 확인 조작만 별도 notice feedback 으로 구분한다. `tools/verify_candidate_save_point_browser.py` 는 8013 기준 `map2_07e` title continue 복원과 직접 quick-load 복원 양쪽에서 `saveNoticeFeedback=save-point-completion-notice-feedback:세이브 완료 1`, `saveNoticeFeedbackRender=True`, `saveNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 요구하고, `tools/verify_web_assets.py`/`tools/summarize_completion_audit.py` 도 같은 marker 를 completion audit evidence 로 보존한다. 이는 완료된 세이브 후보 확인 조작을 실제 플레이 화면/효과음으로 보이게 하는 UX 보강이며, 원본 save point event, event VM runtime, story flag proof 로 승격하지 않는다.

- 2026-06-05 후보 세이브 VM replay 증거 보강: `map2_07e` current-map 세이브 후보는 이제 저장 runtime result, prototype progress detail, auto-save payload, Enter/A action save 모두에 `event-dialogue-block-033` 의 partial replay summary 를 싣는다. `out/candidate_save_point_browser_smoke.*` 는 `vmBlocks=event-dialogue-block-033 vmPartial=True vmFull=False vmRender=2 vmLiteral=2 vmSource=0x00030000` 를 current-map/menu save 와 action save 양쪽에서 기록하고, `tools/verify_web_assets.py` 는 snapshot 내부 `runtimeSave.vmReplays`, `runtimeSave.autoSave.vmReplays`, `progress.lastEvent.detail.vmReplays`, action runtime save 에 같은 block033 replay 가 있는지 구조적으로 확인한다. 이는 save-point 후보가 어떤 EXE 대사 블록에서 나온 것인지 더 좁혀 기록하는 증거 보강이며, 여전히 `originalSavePointRuntimeImplemented=False`, `originalEventVmRuntimeImplemented=False`, completion audit `achieved=False` 를 유지한다.
- 2026-06-06 후보 세이브 candidate evidence 보강: `map2_07e` current-map 세이브 후보 실행은 이제 partial VM replay 뿐 아니라 후보 자체의 `candidateEvidence` 도 runtime result, `save-point-candidate` progress detail, auto-save payload, feedback log/render, Enter/A action save 에 싣는다. `event-dialogue-block-033` evidence 는 `source=event_dialogue_blocks`, `rangeHex=0x004ff47c..0x004ff69c`, `category=statue-shrine-context`, `strength=weak-location-only`, `keywords=신의 산,신의 사자`, `fieldMaps=map2_07e,map2_08e`, `resources=map2_07e.cns,...` 를 보존한다. `tools/verify_candidate_save_point_browser.py` 와 `tools/verify_web_assets.py` 는 `candidateEvidence=event-dialogue-block-033`, `candidateCategories=statue-shrine-context`, `candidateStrengths=weak-location-only` 를 구조/리포트 양쪽에서 확인한다. 이는 후보 저장 gameplay 실행이 어떤 event-derived 후보에서 왔는지 더 직접 보존하는 보강이며, exact statue/save opcode proof 나 원본 save point runtime/story flag proof 로 승격하지 않는다.

- 2026-06-05/07/08 후보 동료 완료 목표 실행 보강: prototype 동료 `린샹`/`스마슈` 가 모두 합류한 뒤 현재 목표가 `후보 동료 완료 map1_02b` / `완료 알림 확인` 으로 바뀌게 했다. 이 상태에서 `목표` 실행은 새 완료 알림 `party-complete:map1_02b` 를 열고, `objectiveAction=party-completion-notice`, `objectiveActiveId=party-complete:map1_02b` 를 남긴다. 완료 알림도 합류 순간과 같은 필드 overlay/WLK 경로를 써서 `partyNoticeFeedback=party-join-completion-notice-feedback:동료 합류 완료 2/2`, `partyNoticeFeedbackRender=True`, `partyNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 기록한다. `tools/verify_candidate_party_join_browser.py` 는 직접 합류 직후, 제목 화면 `이어하기 map1_02b 11,12` 복원, 직접 임시 불러오기 복원에서 이 목표 실행 경로와 완료 피드백을 확인한다. 또한 `event-dialogue-block-003` 완독으로 생긴 린샹 대사 합류는 별도 목표 `후보 대사 합류 완료 map1_02b` / `완료 알림 확인` 으로 바뀌고, 목표 실행은 `dialogue-party-join-complete:map1_02b:event-dialogue-block-003` 알림과 `objectiveAction=dialogue-party-join-completion-notice`, `dialoguePartyNoticeFeedback=dialogue-party-join-completion-notice-feedback:대사 동료 합류 완료 1/1`, `dialoguePartyNoticeFeedbackRender=True`, `dialoguePartyNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 남긴다. 이 보강은 완료된 동료 합류/대사 합류 상태를 현재 목표에서 바로 재확인하는 웹 UX 개선이며, 원본 party join event/story flag runtime proof 로 승격하지 않는다.

- 2026-06-05/07 후보 장비 완료 목표 실행 보강: savedat 없이 시작한 `map1_02b` 새 게임 상태에서 `고양이 발톱` 을 Ataho weapon 으로 장착해 `equipment-prototype` 진행 기록이 생기면 현재 목표가 `후보 장비 완료 map1_02b` / `완료 알림 확인` 으로 바뀌게 했다. 이 상태에서 `목표` 실행은 새 완료 알림 `equipment-complete:map1_02b` 를 열고, `objectiveAction=equipment-completion-notice`, `objectiveActiveId=equipment-complete:map1_02b` 를 남긴다. 완료 알림도 장비 피드백 overlay 경로를 써서 `equipmentNoticeFeedback=equipment-completion-notice-feedback:장비 변경 완료 1/1`, `equipmentNoticeFeedbackRender=True`, `equipmentNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 기록한다. `tools/verify_candidate_equipment_menu_browser.py` 는 장착 직후 직접 임시 불러오기 복원과 제목 화면 `이어하기 map1_02b 11,12` 복원 양쪽에서 이 목표 실행 경로와 완료 피드백을 확인한다. 이 보강은 완료된 웹 prototype 장비 변경을 현재 목표에서 바로 재확인하는 UX 개선이며, 원본 savedat 장비 offset, 원본 장비 효과, story flag runtime proof 로 승격하지 않는다.

- 2026-06-05 후보 도구 완료 목표 실행 보강: savedat 없이 시작한 `map1_02b` 새 게임 상태에서 Ataho 를 HP 24 로 낮춘 뒤 `약초` 를 사용해 HP 36, 약초 0개가 되는 `item-use-prototype` 진행 기록이 생기면 현재 목표가 `후보 도구 완료 map1_02b` / `완료 알림 확인` 으로 바뀌게 했다. 이 상태에서 `목표` 실행은 `item-use-complete:map1_02b` 완료 알림을 열고, `objectiveAction=item-use-completion-notice`, `objectiveActiveId=item-use-complete:map1_02b` 를 남긴다. `tools/verify_title_start_browser.py` 는 직접 임시 불러오기 복원과 제목 화면 `이어하기 map1_02b 11,12` 복원 양쪽에서 HP 24->36, 약초 1->0, 목표 title/action/active id 를 확인한다. 이 보강은 완료된 웹 prototype 도구 사용을 현재 목표에서 바로 재확인하는 UX 개선이며, 원본 아이템 효과 공식, 상태 플래그 offset, story flag runtime proof 로 승격하지 않는다.
- 2026-06-07 후보 도구 완료 알림 피드백 보강: 완료된 `후보 도구 완료 map1_02b` 목표 실행이 알림 대화만 열고 끝나지 않도록, map 화면 위에 `itemNoticeFeedback=inventory-item-completion-notice-feedback:도구 사용 완료 1/1`, `itemNoticeFeedbackRender=True`, `itemNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 남기는 도구 완료 overlay/WLK feedback 을 추가했다. `tools/verify_title_start_browser.py` 는 직접 임시 불러오기 복원과 제목 화면 `이어하기 map1_02b 11,12` 복원 양쪽에서 이 marker 를 확인한다. 이 보강은 완료 목표의 browser-local gameplay 피드백이며, 원본 아이템 효과 공식, 상태 플래그 offset, story flag runtime proof 로 승격하지 않는다.
- 2026-06-08 필드 도구 대상 선택 완료 목표 보강: savedat 없이 시작한 `map1_02b` 새 게임 상태에서 `도구 선택 1` -> `약초 x2` -> 대상 `Rinshan` 선택으로 HP 8->38, 약초 2->1 이 되는 다인 파티 도구 사용도 완료 목표 루프까지 연결해 검증한다. `tools/verify_title_start_browser.py` 는 대상 선택 직후 `objectiveDetail=Rinshan 약초`, `objectiveAction=item-use-completion-notice`, `objectiveActiveId=item-use-complete:map1_02b`, `itemNoticeFeedback=inventory-item-completion-notice-feedback:도구 사용 완료 1/1`, `itemNoticeFeedbackRender=True`, `itemNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 요구한다. 이는 이미 구현된 field inventory target selection 을 목표/알림/overlay/WLK 확인까지 이어 붙이는 웹 gameplay UX 보강이며, 원본 아이템 효과 공식, 상태 플래그 offset, story flag runtime proof 로 승격하지 않는다.

- 2026-06-05 savedat 맵 메뉴 도구 title continue 보강: public savedat 메뉴에서 `약초` 사용과 `해독초` 상태 회복을 거친 뒤 인게임 `임시 저장`/`임시 불러오기` 로 약초 2개, Ataho HP 999, modeled poison 상태, savedat selector field map 후보가 복원되는 기존 검증에 더해, 타이틀 `이어하기 map1_01a ... 세이브 0:0` 로도 같은 상태가 복원되는지 확인한다. `약초` 사용 직후 현재 목표는 `후보 도구 완료 map1_01a` / `완료 알림 확인` 이 되고, `목표` 실행은 `item-use-completion-notice` 로 `item-use-complete:map1_01a` 알림을 열어 `도구 사용 완료 1/1`, `Ataho 약초`, `HP 969 -> 999`, `약초 3 -> 2` 를 표시한다. `tools/verify_mobile_browser_controls.py` 는 title continue 뒤 `titleCount=2`, `titleHp=999`, `titleStatus=['poison']`, field maps `map1_01a/map1_02b`, `routeStatus=not-current-selector`, 그리고 마지막 완료 도구인 `Ataho 해독초` 의 `HP 999 -> 999`, `해독초 1 -> 0` `item-use-complete:map1_01a` 목표 알림 복원을 확인한다. 이는 public savedat 기반 맵 메뉴 도구 사용이 타이틀 재개까지 끊기지 않는 웹 gameplay 저장성 보강이며, 원본 item formula/status flag/story flag proof 로 승격하지 않는다.

- 2026-06-04 후보 세이브 포인트 title 이어하기/액션 우선순위 개선: `map2_07e@11,11` 처럼 save-point 후보와 대사 후보가 같은 좌표에 겹친 경우, 하단 prompt 는 `Enter -> 세이브 후보 1` 을 보여주는데 실제 Enter/A 가 대사 후보를 먼저 여는 불일치가 있었다. `activateHotspotAtFoot()` 의 오브젝트/대사 fallback 우선순위를 prompt 우선순위와 맞춰, 오브젝트 후보가 실제로 있을 때만 오브젝트 경로를 실행하고 save/shop/battle 후보 뒤에 대사 fallback 을 두도록 고쳤다. `tools/verify_candidate_save_point_browser.py` 는 action prompt `Enter -> 세이브 후보 1` 이 실제 save-point 저장으로 이어지고, 제목 화면 `이어하기 map2_07e 11,11` 로 복원해 `세이브 완료 1`, `restoredHp=36`, `restoredMp=8`, `restoredStatuses=none`, 상단 `임시 불러오기` 가 유지되는지 확인한다. 이 변경도 browser-local 후보 저장 UX이며 원본 save point event/story flag proof 로 승격하지 않는다.
- 2026-06-04 후보 액션 우선순위 보정: 위 세이브 포인트 우선순위는 `current-map` save-point 후보에만 적용한다. `web/index.html` 은 `canPrioritizeSavePointCandidateAction()`/`startPrioritySavePointCandidateAction()` 으로 현재 맵 직접 연결 save 후보만 대사/상점보다 앞세우고, `tileset-family` 같은 broad save 후보는 `map4_08n` 의 직접 대사 gate 나 `Enter -> 상점 6` prompt 를 가리지 않게 했다. `tools/verify_candidate_save_point_browser.py`, `tools/verify_candidate_dialogue_progress_browser.py`, `tools/verify_candidate_shop_menu_browser.py` 를 함께 재실행해 `map2_07e` current-map save prompt/action, `map4_08n` direct dialogue prompt/action, `map4_08n` dialogue-gated shop prompt/canvas action 이 모두 유지되는지 확인한다.
- 2026-06-04/07 제목 화면 플레이 진행 시작/이어하기 및 직접 URL 진입 추가: 원본 `map1_01a -> map2_02d` route promotion gate 는 계속 blocked 로 두되, 실제 웹 게임 구현이 거기서 멈추지 않도록 제목 Canvas 메뉴의 기본 선택을 `처음부터` 플레이 루프로 맞췄다. 기존 확정 전환 전용 시작은 `확정 루트` 라벨로 남기고, 기본 Enter/A 는 `playStart` 를 실행한다. 이 항목은 확인된 시작점 `map1_02b@11,12` 로 들어가면서 `trialTransitions=routeAssist`, 기본 후보 목표 `map2_02d`, route path `다음`, 그리고 `encounter=1` 필드 전투 탐색을 한 번에 켜고 즉시 browser-local 임시 저장을 만든다. 2026-06-07 보강으로 `/web/game.html?play=1` 도 같은 routeAssist+field encounter+autosave 플레이 루프로 자동 진입하며 `HWANSE_LAST_TITLE_ROUTE_GOAL.source=query-play-start` 를 남긴다. `tools/verify_title_start_browser.py` 는 기본 title Enter/A 와 query play 양쪽에서 `routeGoal=map2_02d`, HUD `후보 map2_02d`/`전투 0/6`/`저장 있음`, `fieldEncounterMode.source=title-play-start` 또는 `query-play-start`, `HWANSE_LAST_TITLE_ROUTE_GOAL.autoSaved=True` 를 확인한 뒤 제목 화면 `이어하기 map1_02b 11,12 전투 후보 map2_02d` 로 같은 routeAssist+field encounter 상태가 복원되는지 확인한다. 이어서 route `다음`/`후보`/`진입` 버튼이 `map1_01a@11,11`, blocker focus `map1_01a@18,0`, 목표 `map2_02d@47,47` 로 이어질 때 routeAssist URL 에 `routeAutoSave=1` 과 `encounter=1` 을 보존하고, 각 도착 페이지의 `HWANSE_LAST_ROUTE_ASSIST_AUTO_SAVE` 가 현재 `payloadMap`, `routeState.selectedRouteGoal=map2_02d`, `fieldEncounter.enabled=True` 를 저장하는지도 확인한다. 목표 맵 도착 뒤 제목 화면 `이어하기 map2_02d 47,47 전투 후보 map2_02d` 도 같은 routeAssist+field encounter 상태를 복원한다. 이 변경은 플레이 가능한 웹 루프를 첫 화면 또는 직접 URL에서 바로 시작하고 재개하며 다음 후보 맵과 목표 맵에서도 전투/저장을 유지하게 하는 구현 개선이며, 후보 routeAssist 나 prototype encounter 를 원본 정상 route/event proof 로 승격하지 않는다.

- 2026-06-04 필드 전투 승리 자동 저장/이어하기 보강: `grantBattleReward()` 는 prototype field encounter 승리 보상/드롭/진행 기록을 적용한 직후 기존 `quickSaveRuntime()` 으로 browser-local 임시 저장을 갱신한다. `tools/verify_candidate_battle_browser.py` 는 `encounter=1` 에서 자동 진입한 `map1_02b@11,12` 전투 승리 뒤 `autoSaved=True`, `saveMap=map1_02b`, `saveTile=11,12`, `fieldEncounter.stepCount=0`, `fieldEncounterVictoryCount=1`, `battleVictoryCount=0`, `runtimeMoney=75`, 약초 count 2 가 저장 payload 에 남는지 확인한다. 이어서 제목 화면 `이어하기 map1_02b 11,12 전투` 로 돌아가 같은 저장을 불러오면 `encounter=1`, `fieldStep=0/6`, `button=전투 btl_b1`, `quickLoadText=임시 불러오기`, `completionCompleted=False`, 보상 money/drop 이 복원되는지도 확인한다. 이 변경은 `플레이 진행` 으로 시작한 루프에서 걷기 -> 필드 전투 -> 보상 -> 제목 이어하기가 끊기지 않게 하는 구현 개선이며, 원본 encounter table/runtime proof 로 승격하지 않는다.
- 2026-06-05 필드 전투 완료 목표 실행 보강: 반복 가능한 prototype field encounter 승리 상태는 source event battle 후보를 완료시키지 않으므로 `completionCompleted=False`, `button=전투 btl_b1` 를 유지하지만, 별도 `fieldEncounter` completion snapshot 은 `fieldCompletionCompleted=True` 로 노출하게 했다. 이 상태에서 현재 목표는 `후보 필드 전투 완료 btl_b1` / `완료 알림 확인` 으로 바뀌고, `목표` 실행은 `field-encounter-complete:map1_02b` 알림을 열어 `필드 전투 보상 소지금 75 / 경험치 +7`, `필드 전투 드롭 약초 2` 를 보여준다. `tools/verify_candidate_battle_browser.py` 는 직접 필드 전투 승리 직후와 제목 화면 `이어하기 map1_02b 11,12 전투` 복원 뒤 양쪽에서 `objectiveAction=field-encounter-completion-notice`, `objectiveActiveId=field-encounter-complete:map1_02b`, `originalEncounterTableMapped=False`, `originalEncounterRuntimeImplemented=False`, `originalRewardTableMapped=False`, `originalDropTableMapped=False` 를 확인한다. 이 보강은 반복 가능 필드 전투 결과를 현재 목표에서 재확인하는 웹 UX 개선이며 원본 encounter table/runtime/reward/drop/story flag proof 로 승격하지 않는다.

- 2026-06-04 통합 모바일 전투 보상 자동 저장 검증: `tools/verify_mobile_browser_controls.py` 의 manual party 전투 보상 경로도 테스트 코드에서 전투 보상 직후 직접 `quickSaveRuntime()` 을 호출하지 않고, `grantBattleReward()` 가 남긴 `HWANSE_LAST_BATTLE_VICTORY_SAVE` 를 확인한다. 통합 WebKit smoke 는 `autoSource=battle-victory`, `battle-victory` 진행 count 1, 저장 payload 의 money 75, manual party `rinshan,smash`, quick-load 뒤 `quickLoadMoney=75` 와 파티 복원을 확인한다. 이는 실제 플레이에서 후보 전투 승리 보상이 자동 저장되는지 보강하는 검증이며, 원본 battle reward/story flag runtime proof 로 승격하지 않는다.

- 2026-06-04 전투 도주/패배 자동 저장 보강: `endBattlePrototype()` 는 `도주했다.`/`패배했다.` 로 맵에 돌아온 직후에도 `autoSavePrototypeRuntime()` 을 호출해 각각 `HWANSE_LAST_BATTLE_RUN_AUTO_SAVE` 와 `HWANSE_LAST_BATTLE_DEFEAT_AUTO_SAVE` 를 남긴다. `tools/verify_candidate_battle_browser.py` 는 도주가 `autoSource=battle-run`, 패배가 `autoSource=battle-defeat` 로 저장되고 둘 다 `battleVictoryCount=0`, `rewardGranted=False`, `completionCompleted=False` 를 유지하는지 확인한다. 같은 smoke 는 제목 화면 `이어하기 map1_02b 11,12` 로 도주 상태를 복원해 `battleRunCount=1`/소지금 60/EXP 0/`전투 btl_b1` 을 확인하고, 패배 상태도 `battleDefeatCount=1`, `recoveredHp=1`, `quickLoadText=임시 불러오기` 로 복원되는지 확인한다. 패배 경로는 `prototype-battle-defeat-recovery` 뒤 Ataho HP 1이 저장 payload 에도 남는지까지 확인한다. 이 변경은 실제 웹 플레이에서 비승리 전투 결과도 이어하기 가능한 상태로 보존하는 보강이며, 원본 story flag/reward/event VM proof 로 승격하지 않는다.
- 2026-06-05 전투 도주/패배 완료 목표 실행 보강: 비승리 후보 전투 결과는 계속 `battleVictoryCount=0`, `rewardGranted=False`, source battle `completionCompleted=False` 를 유지하지만, 별도 `battleOutcome` completion snapshot 은 `outcomeCompleted=True` 로 노출한다. 도주 직후와 제목 화면 `이어하기 map1_02b 11,12` 복원 뒤 목표는 `후보 전투 도주 btl_b1` 로 바뀌고 `목표` 실행은 `battle-outcome-complete:map1_02b:battle-run` 알림을 열어 보상 없음/소지금 60/경험치 0을 보여준다. 패배 직후와 복원 뒤 목표는 `후보 전투 패배 btl_b1` 로 바뀌고 `battle-outcome-complete:map1_02b:battle-defeat` 알림이 `패배 복구 Ataho HP 1` 을 함께 표시한다. 이 보강은 도주/패배를 실제 웹 플레이 루프에서 확인 가능한 outcome 으로 만든 UX 개선이며, 원본 reward/story flag/event VM proof 로 승격하지 않는다.
- 2026-06-06 전투 도주/패배 화면 피드백 보강: 비승리 후보 전투가 맵으로 돌아올 때 `HWANSE_BATTLE_OUTCOME_FEEDBACK_LOG`/`HWANSE_BATTLE_OUTCOME_FEEDBACK_RENDER` 를 남기고 캔버스 위에 `전투 도주 btl_b1` 또는 `전투 패배 btl_b1` 을 짧게 표시한다. `tools/verify_candidate_battle_browser.py` 는 도주 smoke 에서 `outcomeFeedback=battle-outcome-feedback:전투 도주 btl_b1`, 패배 smoke 에서 `outcomeFeedback=battle-outcome-feedback:전투 패배 btl_b1`, 공통으로 `outcomeFeedbackRender=True`, `outcomeFeedbackDuration=1100`, `browserOutcomeFeedback=True` 를 확인하고, 같은 feedback entry 가 `autoSave.outcomeFeedback` 에도 들어가는지 검증한다. 이 변경은 도주/패배 결과가 로그와 목표 알림에만 묻히지 않고 실제 플레이 화면에서 즉시 보이게 하는 prototype UX 보강이며, 원본 story flag/reward/event VM proof 로 승격하지 않는다.

- 2026-06-04 `플레이 진행` 목표 맵 전투/이어하기 검증 보강: `tools/verify_title_start_browser.py` 는 이제 제목 `플레이 진행` 으로 `map1_02b@11,12 -> map1_01a -> map2_02d@47,47` 까지 이동한 뒤, 목표 맵에서 실제 방향키 이동 입력으로 prototype field encounter 를 발생시켜 `btl_a1` 전투 승리/보상/자동 저장까지 확인한다. 목표 맵 후보 전투는 `boss_2` profile 을 써서 `runtimeMoney=98`, `refresh_water:1`, `herbCount=1`, `fieldEncounterVictoryCount=1`, `battleVictoryCount=0`, `routeCandidateCount=1`, `routeState.selectedRouteGoal=map2_02d` 를 이동 후 좌표의 저장 payload 에 남긴다. 이어서 제목 화면 `이어하기 map2_02d <이동 후 좌표> 전투 후보 map2_02d` 로 돌아가 같은 저장을 불러오면 routeAssist, field encounter, 진행 4, 보상 상태가 복원되는지도 확인한다. 이 변경은 첫 화면 플레이 루프가 실제 걷기 입력, 목표 맵 전투 보상, 제목 이어하기까지 이어지는지 검증하는 보강이며, 후보 전투/routeAssist 를 원본 정상 route/event proof 로 승격하지 않는다.
- 2026-06-04 `플레이 진행` 실제 입력 전환 검증 보강: 같은 title smoke 는 버튼형 route `다음`/`후보`/`진입`과 별도로, `플레이 진행` 시작점에서 실제 `ArrowUp` 입력이 confirmed `map1_02b@11,12 -> map1_01a@11,11` 전환을 타고 `map-transition` 자동 저장을 남기는지 확인한다. 이어 blocker focus `map1_01a@18,0` 에서도 실제 `ArrowUp` 입력이 routeAssist 후보 출구 `map1_01a@18,0 -> map2_02d@47,47` 로 넘어가 `route-candidate` 자동 저장과 제목 `이어하기 map2_02d 47,47 전투 후보 map2_02d` 복원을 남기는지 확인한다. 이는 플레이 가능한 후보 진행을 버튼 점프가 아니라 방향키 조작으로도 이어가게 하는 웹 gameplay 검증이며, 후보 출구를 원본 strict hotspot/selected-root 실행 proof 로 승격하지 않는다.

- 2026-06-04 후보 목표 도착 후 이어가기 보강: routeAssist 목표 맵에 도착하면 웹 런타임은 현재 맵에서 바로 이어갈 수 있는 다음 routeAssist path 를 계산해 HUD 에 `다음 목표 map2_09g` 를 표시하고, `routeNextButton` 자체도 `이어가기` 로 바꿔 오른쪽 버튼만 눌러도 다음 후보 focus 로 이동할 수 있게 했다. 런타임 메뉴에는 기존처럼 `후보 이어가기 map2_09g` 명령을 함께 노출한다. `tools/verify_title_start_browser.py` 는 `플레이 진행` 으로 `map2_02d@47,47` 에 도착한 직후와 제목 `이어하기 map2_02d 47,47 전투 후보 map2_02d` 복원 뒤 모두 `routeNextText=이어가기|도착|완료`, `command=continueRouteAssistPath`, `routeTarget=map2_09g`, `routeNextTarget=map2_09g`, HUD `다음 목표 map2_09g` 가 존재하는지 확인한다. `tools/verify_candidate_route_progress_browser.py` 는 먼저 `routeNextButton` 직접 경로가 `beforeRouteNextText=이어가기`, `beforeContinuationTarget=map2_09g`, `routeNextContinuation=True` 로 `routeGoal=map2_09g`, `transitionTarget=map2_09g`, `routeNextText=진입` 상태를 만드는지 확인한 뒤, 같은 메뉴 명령도 실제 `useSelectedMenuItem()` 경로로 실행해 `routeGoal=map2_09g`, `routePathValue=map2_09g`, `transitionTarget=map2_09g`, `routeNextText=진입`, `runtimeMenuContinuation=True` 로 다음 후보 진입 준비가 되는지 확인한다. 이어 `activateNextRoutePath()` 로 `map2_09g` 에 실제 진입하면 routeAssist URL 의 `routeStepSource=map2_02d`/`routeStepTarget=map2_09g`/`routeStepKind=save-selector-trial` 을 읽어 `progressId=map2_02d->map2_09g`, `routeCandidateCount=1`, `pathProgress=후보 진행 1/2`, `autoSource=routeAutoSave`, `payloadMap=map2_09g`, `runtimeMenuContinuationEntry=True` 자동 저장/진행 기록을 남긴다. `map2_09g` 도착 뒤에는 HUD `다음 목표 map2_10g` 와 메뉴 `후보 이어가기 map2_10g` 를 실제 실행해 source focus 저장이 기존 progress 를 보존한 뒤 `map2_10g` 에 진입하고, `progressId=map2_09g->map2_10g`, `routeCandidateCount=2`, `pathProgress=후보 진행 2/3`, `payloadMap=map2_10g`, `runtimeMenuContinuationChainEntry=True`, 다음 HUD/메뉴 `map2_12h` 까지 확인한다. 이어 제목 화면 `이어하기 map2_10g 25,12` 로 돌아가 `quickLoadText=임시 불러오기`, `routeGoal=map2_10g`, `후보 이어가기 map2_12h`, `routeCandidateCount=2`, `pathProgress=후보 진행 2/3`, `runtimeMenuContinuationTitleRestore=True` 상태가 복원되는지도 확인한다. 복원된 `map2_10g` 에서 다시 같은 메뉴 명령을 실행해 `map2_12h` 에 진입하고 `progressId=map2_10g->map2_12h`, `routeCandidateCount=3`, `pathProgress=후보 진행 3/4`, `payloadMap=map2_12h`, 다음 HUD/메뉴 `map2_14j`, `runtimeMenuContinuationRestoredEntry=True` 를 확인한 뒤, 제목 화면 `이어하기 map2_12h 26,19` 복원에서도 `routeGoal=map2_12h`, `후보 이어가기 map2_14j`, `routeCandidateCount=3`, `pathProgress=후보 진행 3/4`, `runtimeMenuContinuationRestoredTitleRestore=True` 가 유지되는지 확인한다. 마지막으로 복원된 `map2_12h` 에서 `후보 이어가기 map2_14j` 를 실행해 `progressId=map2_12h->map2_14j`, `routeCandidateCount=4`, `pathProgress=후보 진행 4/5`, `payloadMap=map2_14j`, `runtimeMenuContinuationFinalEntry=True` 를 남기고, 제목 화면 `이어하기 map2_14j 18,14` 복원에서 `quickLoadText=임시 불러오기`, `routeGoal=map2_14j`, `routeCandidateCount=4`, `pathProgress=후보 진행 4/5`, `runtimeMenuContinuationFinalTitleRestore=True`, 다음 continuation 없음 상태를 확인한다. 따라서 continuation 은 한 번만 열리는 임시 경로가 아니라 저장/재개 뒤에도 다음 후보로 계속 이어진다. 이 변경은 원본 promotion gate 에 막히더라도 사용자가 웹 플레이에서 다음 후보 맵으로 계속 진행할 수 있게 하는 UX/플레이 루프 개선이며, 후보 routeAssist edge 를 원본 정상 route proof 로 승격하지 않는다.

- 2026-06-04 `목표 실행` 진행 분기 검증 보강: `web/index.html` 의 `activateNextRoutePath()` 는 routeAssist 목표 도착 상태에서 continuation href 를 일반 row href 보다 우선해, `routeNextButton` 과 `목표 실행` 이 같은 다음 후보 준비 상태를 만들게 했다. `tools/verify_candidate_route_progress_browser.py` 는 이제 `목표 실행`을 직접 호출해 `map1_02b` 에서 `objectiveAction action=route-next` 로 `map1_01a` 이동/`routeAutoSave=1` 이 남는지, `map2_02d` 도착 상태에서 `objectiveAction action=route-continuation` 으로 `routeGoal=map2_09g`, `transitionTarget=map2_09g`, `routeNextText=진입` 이 되는지, `map2_14j` 도착 상태에서 `objectiveAction action=field-encounter-enable` 이 `전투 탐색 끄기 0/6`, `autoSource=field-encounter-enable`, `modeSource=objective-action`, `savedPayloadMap=map2_14j` 를 남기는지 확인한다. 같은 smoke 는 메뉴를 열지 않고 키보드 `G` 로 목표를 실행하는 `quickObjectiveKeyboard=True` 경로, 상단 `목표` 버튼으로 첫 route-next 를 실행하는 `quickObjectiveToolbarNext=True` 경로, 모바일 `목` 버튼으로도 첫 route-next 를 실행하는 `quickObjectiveButtonNext=True` 경로, 모바일 `목` 버튼으로 필드 전투 탐색을 켜는 `quickObjectiveButton=True` 경로, 그리고 상단 `목표` 버튼으로 `map2_02d` 도착 상태의 다음 후보 목표를 `map2_09g` 로 고르는 `quickObjectiveToolbar=True` 경로를 검증한다. 첫 상단 버튼 경로는 `source=objective-action-button`, `action=route-next`, `beforeObjectiveButtonText=목표`, `map=map1_01a`, `routeAutoSave=1`, `savedPayloadMap=map1_01a` 를 남기고, 첫 모바일 버튼 경로는 `source=virtual-objective-button`, `action=route-next`, `beforeButtonTitle=목표 실행: 후보 목표 map2_02d`, `map=map1_01a`, `routeAutoSave=1`, `savedPayloadMap=map1_01a` 를 남긴다. continuation 상단 버튼은 `beforeObjectiveButtonTitle=목표 실행: 후보 목표 map2_02d / map2_09g 이어가기` 에서 `objectiveButtonTitle=목표 실행: 후보 목표 map2_09g / map2_09g 이동`, `routeNextText=후보` 상태로 바뀐다. 필드 전투 모바일 버튼 title 은 `목표 실행: 후보 목표 map2_14j / 걸어서 필드 전투 0/6` 으로 현재 다음 행동을 드러낸다. 이 보강은 메뉴에서 목표를 읽는 데서 끝나지 않고 현재 목표를 실제 플레이 행동으로 실행하게 하는 UX/플레이 루프 개선이며, 후보 routeAssist/field encounter 를 원본 normal-route 또는 encounter runtime proof 로 승격하지 않는다.
- 2026-06-06 `목표 실행` WLK 효과음 마커 보강: `activateQuickObjectiveAction()` 성공 경로가 기존 `menuConfirm` 재생을 유지하면서 `quick-objective-sound` marker 를 남긴다. 키보드 `G`, 상단 `목표`, 모바일 `목` 의 route-next/route-continuation/field-encounter-enable 경로는 모두 `quickObjectiveSound=quick-objective-sound:<입력>:<행동>`, `quickObjectiveSoundSrc=../extract_wlk/04.wav`, `quickObjectiveSoundPlayed=True` 를 기록한다. `tools/verify_candidate_route_progress_browser.py` 는 route-next 처럼 전환 뒤 전역 sound counter 가 초기화되는 경우에도 sessionStorage 에 보존된 marker 를 확인하고, 같은 페이지에 남는 field encounter/continuation 경로에서는 `menuConfirmSoundCount=1` 도 함께 확인한다. 이 보강은 목표 실행 버튼/키가 실제 런타임 피드백까지 발생시키는지 검증하는 플레이 UX 개선이며, 원본 normal-route/story flag proof 로 승격하지 않는다.
- 2026-06-06 후보 경로 `다음/이어가기` 버튼 WLK 효과음 마커 보강: 직접 `routeNextButton` 클릭은 새 `activateRouteNextButton()` 래퍼를 통해 `activateNextRoutePath()` 를 실행하고, 성공 시 `route-control-sound` marker 를 남긴다. `tools/verify_candidate_route_progress_browser.py` 는 `map2_02d` 도착 상태의 `이어가기` 버튼 실행에서 `routeControlAction=route-continuation`, `routeControlSound=route-control-sound:route-next-button:route-continuation`, `routeControlSoundSrc=../extract_wlk/04.wav`, `routeControlSoundPlayed=True` 를 확인한다. 내부 목표 실행 경로와 중복 재생되지 않도록 `activateNextRoutePath()` 자체가 아니라 실제 버튼 래퍼에만 적용했다. 이 보강은 상단 후보 진행 버튼도 WLK 피드백이 있는 실제 플레이 조작으로 맞추는 UX 개선이며, 원본 route promotion proof 로 승격하지 않는다.

- 2026-06-04 후보 이어가기 전투 탐색 보존 보강: `tools/verify_candidate_route_progress_browser.py` 의 continuation 경로도 이제 `encounter=1` 상태에서 시작해 `map2_02d -> map2_09g -> map2_10g -> map2_12h -> map2_14j` 후보 이어가기를 검증한다. 각 `routeAutoSave` 진입은 현재 맵 기준 `fieldEncounter.enabled=True`, `stepCount=0`, `lastMap=<target map>`, `fieldEncounterMenuLabel=전투 탐색 끄기 0/6`, 저장 payload 의 `savedFieldEncounter.lastMap=<target map>`, HUD `전투 0/6` 를 함께 확인한다. 제목 화면 복원 label 도 `이어하기 map2_10g 25,12 전투 후보 map2_10g`, `이어하기 map2_12h 26,19 전투 후보 map2_12h`, `이어하기 map2_14j 18,14 전투 후보 map2_14j` 로 전투 탐색 상태를 표시한다. 이 변경은 `플레이 진행`에서 켠 필드 전투 탐색이 후보 맵 이어가기와 title continue 뒤에도 끊기지 않게 하는 웹 gameplay 보강이며, 원본 encounter table/runtime proof 로 승격하지 않는다.

- 2026-06-04 후보 이어가기 후 실제 전투 탐색 검증 보강: 같은 route continuation smoke 는 이제 최종 후보 맵 `map2_14j` title 복원 뒤에도 멈추지 않고, 실제 방향키 이동 입력으로 prototype field encounter 를 발동시킨다. `map_j` 계열 후보 `event-dialogue-block-010:btl_j1` 전투가 열리고 승리 처리 뒤 `field-encounter-victory` 자동 저장이 `saveMap=map2_14j`, 이동 후 좌표, `routeState.selectedRouteGoal=map2_14j`, `fieldEncounter.stepCount=0`, `routeCandidateCount=4`, `battleStartCount=1`, `fieldEncounterCount=1`, `fieldEncounterVictoryCount=1`, `battleVictoryCount=0` 를 남기는지 확인한다. 또한 `publishPrototypeCompletionState()` 의 route snapshot 이 `completionCompleted=True`, `completionSource=prototype-route-assist-completion`, `completionRouteCandidateCount=4`, `completionFieldEncounterVictoryCount=1` 을 즉시 승리 상태와 제목 `이어하기 map2_14j <이동 후 좌표> 전투 후보 map2_14j 완료 map2_14j` 복원 상태 양쪽에서 유지하는지 확인한다. 완료 뒤 플레이 HUD 는 `후보 map2_14j  완료`, 상태줄 `완료 map2_14j`, 목표줄 `목표 후보 루트 완료 map2_14j`/`다음 완료 버튼으로 결과 확인` 을 보여 내부 marker 와 다음 행동이 실제 플레이 화면에 드러나는지도 검증한다. 이어 완료 상태의 `routeNextButton` 은 `완료` 로 바뀌고, 클릭하면 `route-complete:map2_14j` 대화가 열려 `후보 루트 완료 map2_14j`, `후보 진행 4`, `필드 전투 승리 1`, `원본 normal-route/story flag 실행 증명은 아직 아닙니다.` 를 표시하며 `routeCompleted=1`, `runtimeRouteCompletionNotice=True`, `originalRoutePromotionImplemented=False` 를 남기는지도 검증한다. 완료 안내는 이제 `route-complete` 진행 기록을 중복 없이 남기고 `autoSource=route-complete`, `savedPayloadMap=map2_14j`, `routeCompleteCount=1` 로 자동 저장하며, 진행 리뷰도 `후보 완료 1` 과 `route-complete:map2_14j` 를 표시한다. 같은 완료 상태에서 런타임 메뉴 `목표 실행` 과 메뉴의 `후보 완료 map2_14j` 명령도 동일한 완료 대화를 열고, 각각 `objectiveAction=route-completion-notice`, `objectiveActiveId=route-complete:map2_14j`, `menuCommand=후보 완료 map2_14j`, `menuActiveId=route-complete:map2_14j` 를 남긴다. 이 변경은 후보 맵을 계속 이동한 뒤 실제 걷기 -> 전투 -> 승리 저장 -> 제목 이어하기 -> browser-local completion marker/HUD/title label -> 완료 진행 기록/저장 -> 완료 안내 대화까지 이어지는 웹 gameplay 검증이며, 후보 전투/encounter/routeAssist completion 을 원본 encounter table/runtime 또는 normal-route proof 로 승격하지 않는다.

- 2026-06-04 웹 후보 완료 게이트 보강: routeAssist 완료 안내는 이제 `route-complete` 기록/자동 저장 뒤 `routePrototypeCompletionGateState()` 를 통해 `playableGate=prototype-playable-route-gate`, `playableGateStatus=open`, `playableGateOpen=True`, `playableGateLabel=웹 후보 루트 완료 map2_14j`, `originalFullGameCompletionImplemented=False` 를 노출한다. 완료 대화에는 `웹 후보 루트 완료 게이트가 열렸습니다.` 라인을 추가했고, `publishPrototypeCompletionState()` 는 `playableGate`/`playableGateOpen` 을 함께 게시한다. `tools/verify_candidate_route_progress_browser.py` 와 `tools/verify_web_assets.py` 는 브라우저에서 후보 루트를 실제로 진행해 전투 승리, 제목 이어하기 복원, 완료 버튼/목표 실행/메뉴 완료 명령까지 확인한 뒤 이 gate marker 를 검사한다. 또한 완료 안내 자동 저장 뒤 다시 제목 화면으로 돌아가 `이어하기 map2_14j ... 완료 map2_14j` 를 누르면 `savedRouteCompleteCount=1`, `completionRouteCompleteCount=1`, `completionItem=후보 완료 map2_14j`, `runtimeRouteCompletionGateTitleRestore=True` 로 완료 게이트가 복원되는지도 검증한다. 복원된 런타임 메뉴의 `후보 완료 map2_14j` 명령은 완료 대화를 다시 열되 `duplicateProgress=True`, `savedRouteCompleteCount=1`, `runtimeRestoredRouteCompletionMenuNotice=True` 로 `route-complete` 기록을 중복 증가시키지 않는다. 완료 저장이 있는 제목 메뉴에는 이제 `후보 완료 map2_14j` 항목도 노출되며, 선택 시 `title-route-completion-gate`, `payloadRouteCompleteCount=1`, `playableGateOpen=True`, `duplicateProgress=True`, `runtimeTitleRouteCompletionGate=True` 로 저장을 불러와 완료 대화를 바로 연다. `tools/summarize_completion_audit.py` 는 이에 따라 `completion-gate` 를 `missing` 에서 `partial` 로 올리지만, 이 gate 는 browser-local routeAssist completion 이며 원본 full-game ending, normal-route promotion, story flag completion 이 아니므로 top-level `achieved=False` 는 유지한다.
- 2026-06-04 웹 후보 클리어 요약 보강: 완료 저장이 있는 런타임 메뉴에는 `후보 클리어 map2_14j`, 아직 클리어가 저장되지 않은 제목 메뉴에는 `후보 클리어 저장 map2_14j` 경로를 추가했다. 제목 메뉴에서 이 항목을 선택하면 `title-route-clear-gate` 로 저장을 불러와 `route-clear:map2_14j` 대화를 열고, `route-clear` 진행 기록과 `routeClearAutoSource=route-clear` 자동 저장을 중복 없이 남긴다. 클리어 요약 대화는 이제 `진행 기록 9`, `결과 소지금 80 / 보상 약초 2` 도 표시하고, 진행 기록 리뷰에도 `클리어 목표 map2_14j`, `클리어 진행 기록 9`, `클리어 결과 소지금 80 / 보상 약초 2` 를 남긴다. smoke 는 `routeClearCount=1`, `payloadRouteClearCount=1`, `titlePayloadClearCount=1`, `titlePayloadLabel=후보 클리어 map2_14j`, `progressReviewRouteClear=True`, 제목 `이어하기 ... 클리어 map2_14j`, 런타임 메뉴 `후보 클리어 map2_14j`, `runtimeTitleRouteClearGate=True` 를 확인한다. 또한 클리어 저장 뒤 제목 `이어하기 ... 클리어 map2_14j` 를 눌러 복원하면 `runtimeRouteClearGateTitleRestore=True`, `savedRouteClearCount=1`, `completionRouteClearCount=1`, `clearItem=후보 클리어 map2_14j` 가 유지되고, 플레이 화면의 route 버튼/HUD/목표도 `routeNextText=클리어`, `후보 루트 클리어 map2_14j`, `다음 클리어 요약 확인`, `클리어 map2_14j` 로 바뀐다. 이 상태에서 `목표` 액션과 route 버튼 `클리어` 클릭은 둘 다 `route-clear:map2_14j` 요약을 열며 `runtimeRouteClearObjectiveAndButton=True`, `objectiveDuplicateProgress=True`, `buttonDuplicateProgress=True` 로 `route-clear` 기록을 중복 증가시키지 않는다. 복원된 런타임 메뉴의 `후보 클리어 map2_14j` 를 다시 열어도 `duplicateProgress=True`, `runtimeRestoredRouteClearMenuSummary=True` 를 유지한다. 이 역시 browser-local 후보 루트 클리어 요약이며 `originalFullGameCompletionImplemented=False` 를 유지하므로 원본 엔딩/스토리 플래그 완료로 승격하지 않는다.
- 2026-06-05 웹 후보 완료/클리어 overlay 보강: routeAssist 완료/클리어 게이트가 대화와 자동 저장에만 묻히지 않도록 `route-complete` 안내를 열 때 필드 화면 위에 `후보 완료 map2_14j`, `route-clear` 요약을 열 때 `후보 클리어 map2_14j` overlay 를 1.3초 동안 표시한다. `web/index.html` 은 `HWANSE_ROUTE_GATE_FEEDBACK_LOG`, `HWANSE_LAST_ROUTE_GATE_FEEDBACK`, `HWANSE_ROUTE_GATE_FEEDBACK_RENDER`, `HWANSE_LAST_ROUTE_GATE_FEEDBACK_RENDER` 를 노출하고, `tools/verify_candidate_route_progress_browser.py` 는 8013 기준 완료 안내/제목 완료 게이트에서 `routeGateFeedback=route-completion-feedback:후보 완료 map2_14j`, 클리어 제목 게이트/목표 버튼/route 버튼에서 `routeGateFeedback=route-clear-feedback:후보 클리어 map2_14j`, 양쪽 `routeGateFeedbackRender=True`, `durationMs=1300`, `playableGateStatus=open`, `browserRouteGateFeedbackImplemented=True` 를 확인한다. 이 피드백은 browser-local 후보 완료/클리어 순간을 플레이 화면에 즉시 보이게 하는 UX 보강이며, 원본 full-game ending/normal-route promotion/story flag proof 로 승격하지 않고 `originalFullGameCompletionImplemented=False`, `originalRoutePromotionImplemented=False`, `originalStoryFlagRuntimeImplemented=False` 를 유지한다.
- 2026-06-07 웹 후보 완료/클리어 WLK sound 보강: `recordRouteGateFeedback()` 은 이제 후보 루트 완료/클리어 overlay 를 만들 때 추출 WLK `victory` 사운드(`../extract_wlk/12.wav`)를 함께 재생하고 `routeGateSound=victory`, `routeGateSoundSrc=../extract_wlk/12.wav`, `routeGateSoundPlayed=True` 를 feedback/render snapshot 에 남긴다. `tools/verify_candidate_route_progress_browser.py` 는 8013 기준 route-complete 안내, 제목 완료 게이트, title route-clear 게이트, 클리어 목표/route 버튼 재열기에서 이 sound marker 를 확인하고, `tools/verify_web_assets.py` 와 completion audit 도 같은 evidence 를 요구한다. 이는 routeAssist browser-local 완료/클리어 순간의 플레이 피드백을 전투 승리 WLK 자산과 연결하는 UX 보강이며, 원본 full-game ending/normal-route promotion/story flag proof 로 승격하지 않는다.
- 2026-06-07 장거리 후보 완료 WLK sound 검증 보강: `tools/verify_candidate_deep_route_browser.py` 도 이제 `map1_02b -> ... -> map5_40f` 장거리 routeAssist 체인을 끝낸 뒤 `route-complete:map5_40f` 안내에서 `routeGateFeedback=route-completion-feedback:후보 완료 map5_40f`, `routeGateFeedbackRender=True`, `routeGateSound=victory`, `routeGateSoundSrc=../extract_wlk/12.wav`, `routeGateSoundPlayed=True` 를 모두 요구한다. `tools/verify_web_assets.py` 는 deep-route smoke markdown/json 과 completion audit normal-progression evidence 에서 같은 marker 를 확인한다. 이는 이미 붙인 완료 WLK feedback 이 짧은 `map2_14j` 후보뿐 아니라 장거리 후보 루트 완료 순간에도 실제 브라우저 검증을 통과한다는 coverage 보강이며, 원본 normal-route promotion/runtime proof 로 승격하지 않는다.
- 2026-06-05 routeAssist 후보 진행 overlay 보강: routeAssist 후보 전환이 저장될 때 완료 대화 전까지 조용히 지나가지 않도록 `route-candidate` 자동 저장 직후 필드 화면 위에 `후보 진행 1/2 map2_02d`, `후보 완료 2/2 map2_18d`, continuation entry 에서는 `후보 진행 1/2 map2_09g`..`후보 진행 4/5 map2_14j` overlay 를 1.2초 동안 표시한다. `web/index.html` 은 `HWANSE_ROUTE_PROGRESS_FEEDBACK_LOG`, `HWANSE_LAST_ROUTE_PROGRESS_FEEDBACK`, `HWANSE_ROUTE_PROGRESS_FEEDBACK_RENDER`, `HWANSE_LAST_ROUTE_PROGRESS_FEEDBACK_RENDER` 를 노출하고, `tools/verify_candidate_route_progress_browser.py` 는 8013 기준 첫 후보 전환/체인 전환/routeAutoSave continuation entry 에서 `routeProgressFeedback=route-progress-feedback:...`, `routeProgressFeedbackRender=True`, `durationMs=1200`, `browserRouteProgressFeedbackImplemented=True`, `prototypeRouteAssistProgressImplemented=True` 를 확인한다. 이 변경은 browser-local 후보 진행을 플레이 화면에 즉시 보이게 하는 UX 보강이며, 원본 normal-route promotion/story flag proof 로 승격하지 않고 `originalRoutePromotionImplemented=False`, `originalStoryFlagRuntimeImplemented=False` 를 유지한다.
- 2026-06-07 routeAssist 후보 진행 WLK sound 보강: `recordRouteProgressFeedback()` 은 이제 후보 진행/완료 overlay 를 만들 때 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 재생하고 feedback/render snapshot 및 자동 저장 payload 에 `routeProgressSound=menuConfirm`, `routeProgressSoundSrc=../extract_wlk/04.wav`, `routeProgressSoundPlayed=True` 를 남긴다. `tools/verify_candidate_route_progress_browser.py` 는 8013 기준 첫 `map1_01a -> map2_02d` 후보 진행, `map1_01a -> map2_02d -> map2_18d` 후보 완료, `map2_09g`..`map2_14j` routeAutoSave continuation entry 들에서 이 sound marker 를 요구한다. 이 보강은 후보 루트가 조용히 저장되는 것이 아니라 실제 플레이 피드백과 함께 진행되도록 맞추는 UX 개선이며, 원본 normal-route promotion/story flag proof 로 승격하지 않는다.
- 2026-06-07 routeAssist trial-only blocker 전파 보강: `map1_01a -> map2_02d` 후보 전환이 live waypoint HUD 에만 blocker 를 표시하고 저장/진행 기록에서는 조용히 `route-candidate` 로 남던 상태를 정리했다. `mapExitCandidateBlockerDetail()` 과 `requestedRouteAssistStepBlockerDetail()` 이 `out/web_playtest_route.*` 의 strict hotspot blocker row 를 찾아 `blockReasons=5`, `strictHotspotStatus=blocked`, `promotionBlockSummary`, `routePromotionStatus=trial-only`, `routeBlockerShortText=trial-only: no map1_01a->map2_02d transition-review row +4` 를 생성한다. 이 값은 movement 후보 전환, `routeAutoSave=1` direct target 진입, 자동 저장 payload, progress event detail, source prompt, `route-progress-feedback`, `route-candidate-feedback` transition overlay 에 모두 보존된다. `tools/verify_candidate_route_progress_browser.py` 는 첫 후보 이동의 recorded route/source prompt 에서 blocker fields 를 확인하고, `tools/verify_title_start_browser.py` 는 title start flow 의 direct route target autosave 와 실제 ArrowUp 후보 이동 transition feedback 이 같은 blocker 를 갖는지 8013 기준으로 검증한다. 이 변경은 후보 경로가 저장/복원/피드백 전 계층에서 정식 normal-route 가 아닌 trial-only 상태임을 일관되게 보이게 하는 웹 gameplay/증거 정합성 보강이며, strict source hotspot, real selector `2:0`, selected-root execution proof 부재는 계속 route promotion blocker 로 남긴다.
- 2026-06-05 후보 클리어 메뉴 정합성 보강: 클리어 저장을 복원한 뒤 기본 후보 진행 메뉴와 제목 메뉴가 더 이상 stale `후보 완료 map2_14j` 항목이나 title continue 의 `완료 map2_14j` suffix 를 남기지 않고 바로 `후보 클리어 map2_14j` 요약으로 이어지게 했다. `tools/verify_candidate_route_progress_browser.py` 는 title continue 복원 뒤 `titleRouteCompletionLabelHidden=True`, `titleRouteCompletionHidden=True`, `titleRouteClearVisible=True`, `completionItem=-`, `clearLabelCount=1`, `clearItem=후보 클리어 map2_14j`, `routeNextText=클리어` 를 확인한다. 이는 클리어 뒤 HUD/목표/route 버튼/런타임 메뉴/제목 메뉴가 모두 같은 클리어 상태를 가리키게 하는 웹 gameplay UX 정합성 보강이며, 원본 full-game ending/story flag 완료로 승격하지 않는다.

- 2026-06-05 후보 오브젝트 충돌/overlay 보강: `scene_events.js` 에서 연결된 visible z*.cns 오브젝트 후보는 이제 normal map view 에서 보이는 것에 그치지 않고 기본적으로 anchor tile 이동을 막는다. `objectCollision=0` 으로 끌 수 있고, 디버그 HUD/snapshot 에 `objectCollisionEnabled`, `collisionAnchorCount`, `collisionBlocks` 를 노출한다. collision overlay/overview overlay 에도 같은 block tile 을 `obj 3` 로 표시해 보이는 오브젝트와 통행 불가 칸이 맞물리게 했다. `tools/verify_candidate_event_object_browser.py` 는 `map2_03l@11,12` 에서 위쪽 `11,11` anchor 로 이동하려는 `canMoveToTarget`/`movementTargetFromTile` 이 `blocked=True`, `anchors=3`, `primary=None`, `directCanMove=False` 로 막히면서도 facing prompt `Enter -> 조사 zg_kni 3개` 는 유지되는지 확인하고, `collision=1` 상태에서 `collisionOverlay=map2_03l`, `objectTiles=1`, `objectAnchors=3`, `visible=1`, `tile=11,11`, `assets=zg_kni,zm_2,zs_rg` 가 렌더 snapshot 에 남는지도 검증한다. 같은 smoke 는 `objectCollision=0` opt-out 에서 `objectCollisionDisabled=map2_03l`, `enabled=False`, `directCanMove=True`, `primaryTile=11,11`, `anchors=0`, `blocked=False` 가 되면서도 조사 prompt 는 유지되는지 확인한다. 이 변경은 웹 gameplay 충돌/조사 UX 보강이며, 원본 NPC/object VM 실행 proof 로 승격하지 않는다.

- 2026-06-05 이동 cadence 브라우저 검증 보강: `tools/verify_candidate_movement_browser.py` 를 추가해 WebKit 런타임에서 deterministic step update 를 직접 확인한다. `map1_02b@11,12 -> 12,12` 한 칸 이동이 `frameMs=48`, `tileStepMs=192`, `commands=4`, original walk `cadence=8`, `walkFrames=5` 를 쓰고, 샘플 `start:160,176:f0:p0:foot11,12`, `tick1:164,176:f1:p1:foot11,12`, `tick2:168,176:f2:p2:foot11,12`, `tick3:172,176:f3:p3:foot11,12`, `tick4:176,176:f0:p0:foot12,12`, `idle-after-complete:176,176:f0:p0:foot12,12` 순서로 기록되는지 검증한다. 같은 trace 는 right-facing 원본 selector cadence `start:3,tick1:17,tick2:16,tick3:3,tick4:16,idle-after-complete:3`, source rect `240,64,48x64 -> 336,64,48x64 -> 288,64,48x64 -> 240,64,48x64 -> 288,64,48x64 -> 240,64,48x64`, `sourceMatches=True` 도 함께 고정한다. 즉 웹 movement loop 의 frame-quantized position, 보행 frame, script phase, footTile 변경 시점, 원본 selector/source-rect mapping 을 브라우저 산출물 `out/candidate_movement_browser_smoke.*` 로 고정한다. 이는 웹 구현 검증 보강이며, 원본 actor interpolation proof 나 current selector 2:0 active order proof 로 승격하지 않는다.
- 2026-06-06 필드 이동 WLK step 효과음 마커 보강: 실제 `ArrowRight` 입력으로 `map1_02b@11,12 -> 12,12` 한 칸 이동을 시작할 때 `playSound("step")` 결과를 `field-movement-sound` marker 로 남긴다. `tools/verify_candidate_movement_browser.py` 는 `input=keyboard-movement`, `from=11,12`, `target=12,12`, `after=12,12`, `stepActiveAfterInput=True`, `stepActiveAfterComplete=False`, `fieldMovementSound=field-movement-sound:step`, `fieldMovementSoundSrc=../extract_wlk/00.wav`, `fieldMovementSoundPlayed=True`, `stepSoundCount=1`, `browserFieldMovementSound=True` 를 확인한다. 이 보강은 실제 필드 조작이 화면 이동뿐 아니라 추출 WLK step 피드백까지 발생시키는지 검증하는 웹 gameplay UX 개선이며, 원본 step sound timing, actor movement runtime, story flag proof 로 승격하지 않는다.
- 2026-06-05 이동 막힘 bump 피드백 보강: 충돌이나 필드 상태로 이동이 막힐 때 플레이어가 idle 로만 돌아가던 상태에 짧은 타일 pulse 를 추가했다. `web/index.html` 은 `HWANSE_MOVEMENT_BUMP_LOG`, `HWANSE_LAST_MOVEMENT_BUMP_EFFECT`, `HWANSE_LAST_MOVEMENT_BUMP_RENDER` 를 노출하고, `movement-collision` 과 `field-status-movement-block` 모두 `durationMs=220` bump marker 를 남긴다. `tools/verify_candidate_movement_browser.py` 는 `map1_02b` 런타임에서 실제 `chooseMovementStep` 이 null 이 되는 충돌 입력을 찾아 실행한 뒤 `source=movement-collision`, `reason=collision`, `playerStayed=True`, `stepActive=False`, `render=True`, `browserBump=True`, `originalObjectScriptCollisionRuntimeImplemented=False` 를 확인한다. 이는 막힌 방향을 플레이어가 눈으로 인지할 수 있게 하는 웹 gameplay 피드백 보강이며, 원본 object script collision VM proof 로 승격하지 않는다.
- 2026-06-06 이동 막힘 WLK bump 효과음 마커 보강: 새 bump effect 가 생성될 때 기존 WLK `menuMove` 효과음을 재사용해 `movement-bump-sound` marker 를 남긴다. `tools/verify_candidate_movement_browser.py` 는 실제 blocked movement 입력에서 `bumpSound=movement-bump-sound:menuMove`, `bumpSoundSrc=../extract_wlk/03.wav`, `bumpSoundPlayed=True`, `bumpSoundCount=1`, `browserBumpSound=True` 를 확인하고, 같은 marker 가 bump effect 의 `sound` detail 에도 보존되는지 검증한다. 이는 막힌 방향 조작이 화면 pulse 뿐 아니라 즉각적인 WLK 피드백도 주도록 하는 웹 gameplay UX 개선이며, 원본 object script collision VM, DirectSound timing, story flag proof 로 승격하지 않는다.
- 2026-06-05 필드 poison/paralysis 이동 효과 보강: 맵 이동 완료 시 poison 상태인 prototype/runtime 캐릭터는 `FIELD_POISON_STEP_INTERVAL=4` 타일 이동마다 `field-status-effect-prototype` 을 기록하고 HP 를 감소시키며, 결과를 자동 저장한다. 피해 전 1-3걸음 카운터도 `field-status-step-prototype` 으로 자동 저장해 중간 재개 시 `fieldPoisonStepCount` 가 끊기지 않게 했다. paralysis 상태는 `FIELD_PARALYSIS_MOVE_INTERVAL=3` 유효 이동 시도마다 `field-status-movement-block-prototype` 을 기록하고 해당 이동을 한 번 차단하며, 차단 전 1-2회 카운터도 실제 이동 완료 뒤 `field-status-movement-step-prototype` 으로 자동 저장한다. HUD 에는 `상태 Ataho 마비 이동 실패` 를 표시하고 상태 메뉴는 중간 카운터를 `필드 마비 2/3` 으로 보여준다. 하단 플레이 HUD 도 파티 줄의 `Ataho HP 34/36 독` 과 최근 필드 상태 피해 `상태 Ataho 독 -2 HP 34` 를 보여준다. 제목 화면 `이어하기` 라벨도 저장 payload 의 상태를 읽어 `상태 독`/`상태 마비` 를 붙인다. 독 피해나 마비 이동 실패가 발생하면 현재 목표가 `후보 필드 상태 완료 map1_02b` / `완료 알림 확인` 으로 바뀌고, 목표 실행은 `field-status-completion-notice` 로 `field-status-complete:map1_02b` 알림을 열어 poison 은 `Ataho HP 36->34`, `피해 2`, paralysis 는 `Ataho 마비`, `이동 실패`, `이동 3회마다 차단` 을 보여준다. `tools/verify_candidate_movement_browser.py` 는 `map1_02b` 에서 Ataho 를 `poison`/HP36 으로 둔 뒤 네 번 이동해 `hp=36->34`, `damage=2`, `partialCounter=2`, `partialAutoSource=field-status-step-prototype`, `progressCount=1`, `autoSource=field-status-effect-prototype`, `savedHp=34`, `savedPoison=True`, `objectiveAction=field-status-completion-notice`, `objectiveActiveId=field-status-complete:map1_02b`, `partyHud=True`, `hud=True` 가 남는지 확인한다. 별도 partial continue 경로는 두 걸음 뒤 제목 `이어하기 map1_02b 11,12 상태 독` 로 복원해 `titleContinue=True`, `statusLabel=True`, `savedCounter=2`, `restoredCounter=2`, `restoredHp=36`, `restoredPoison=True`, `quickLoadText=임시 불러오기`, `statusMenu=True` 를 확인한다. 해독초 poison cure continue 경로는 `counter=2->0`, `restoredPoison=False`, `statusLabel=False`, `hud=False`, `statusMenu=False`, `autoSource=item-use-prototype` 를 확인해 치료 뒤 title/HUD/status-menu 에 독 상태가 남지 않음을 검증한다. 해독초 paralysis cure continue 경로는 `fieldParalysisMoveCount` 결과/autosave 를 `counter=2->0` 으로 남기고 `restoredParalysis=False`, `statusLabel=False`, `hud=False`, `statusMenu=False`, `staleCleared=True`, `autoSource=item-use-prototype` 를 확인해 치료 뒤 title/HUD/status-menu 와 최근 movement block/step 캐시에 마비 상태가 남지 않음을 검증한다. 독 피해 후 effect continue 경로는 제목 `이어하기` 로 돌아간 뒤 `savedHp=34`, `restoredHp=34`, `restoredPoison=True`, `autoSource=field-status-effect-prototype`, `objective=후보 필드 상태 완료 map1_02b`, `objectiveAction=field-status-completion-notice`, `objectiveActiveId=field-status-complete:map1_02b`, `hud=True` 를 확인해 실제 피해가 저장된 상태에서도 완료 목표/알림이 복원됨을 검증한다. 마비 movement 경로는 세 번의 유효 이동 시도에서 `attempts=3`, `blocked=1`, `statusLabel=True`, `restoredParalysis=True`, `autoSource=field-status-movement-block-prototype`, `objectiveAction=field-status-completion-notice`, `objectiveActiveId=field-status-complete:map1_02b`, `hud=True`, `statusMenu=True` 를 확인하고, 별도 마비 partial continue 경로는 두 번 이동 뒤 `savedCounter=2`, `restoredCounter=2`, `autoSource=field-status-movement-step-prototype`, `statusMenu=True` 를 확인한다. 이는 전투 밖에서도 상태이상이 이동 gameplay 에 영향을 주게 하는 웹 prototype 보강이며, 원본 상태 공식/상태 flag/story flag proof 로 승격하지 않는다.
- 2026-06-07 필드 상태이상 WLK sound marker 보강: `recordFieldStatusFeedback()` 은 이제 실제 HP 를 깎는 poison 피해 feedback 에 `battleHit` WLK 사운드(`../extract_wlk/09.wav`)를, paralysis 이동 차단 feedback 에 `menuMove` WLK 사운드(`../extract_wlk/03.wav`)를 연결하고 feedback/render snapshot 에 `fieldStatusSound`, `fieldStatusSoundSrc`, `fieldStatusSoundPlayed` 를 남긴다. 단순 카운터 표시(`독 2/4`, `마비 2/3`)는 소리를 내지 않는다. `tools/verify_candidate_movement_browser.py` 는 8013 기준 poison 피해에서 `statusSound=battleHit`, `statusSoundSrc=../extract_wlk/09.wav`, `statusSoundPlayed=True`, paralysis 차단에서 `statusSound=menuMove`, `statusSoundSrc=../extract_wlk/03.wav`, `statusSoundPlayed=True` 를 확인한다. 이는 전투 밖 상태이상 효과가 화면/HUD/저장뿐 아니라 WLK 효과음 provenance 도 갖게 하는 웹 gameplay UX 보강이며, 원본 상태 공식/DirectSound timing/story flag proof 로 승격하지 않는다.
- 2026-06-07 필드 상태 완료 알림 피드백 보강: `field-status-completion-notice` 목표 실행이 `field-status-complete:map1_02b` 대화만 열던 상태에서 `field-status-completion-notice-feedback` overlay 와 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)도 남기도록 했다. `tools/verify_candidate_movement_browser.py` 는 poison 완료/poison effect continue/paralysis movement 경로에서 `noticeFeedback=field-status-feedback:field-status-completion-notice-feedback:필드 상태 완료 1/1`, `noticeFeedbackRender=True`, `noticeSound=menuConfirm`, `noticeSoundSrc=../extract_wlk/04.wav`, `noticeSoundPlayed=True` 를 확인한다. 이는 필드 상태이상 완료 목표를 눌렀을 때 플레이어가 시각/청각 피드백을 받게 하는 웹 gameplay UX 보강이며, 원본 상태 공식/DirectSound timing/story flag proof 로 승격하지 않는다.
- 2026-06-06 필드 상태이상 캔버스 피드백 보강: poison 피해와 paralysis 이동 차단이 HUD/자동 저장에만 머물지 않도록 `field-status-feedback` overlay 를 추가했다. `web/index.html` 은 `FIELD_STATUS_FEEDBACK_DURATION_MS=1100`, `HWANSE_FIELD_STATUS_FEEDBACK_LOG`, `HWANSE_LAST_FIELD_STATUS_FEEDBACK_RENDER` 를 노출하고, poison 피해는 `Ataho 독 -2 HP 34`, paralysis 차단은 `Ataho 마비 이동 실패` 를 캔버스에 렌더링한다. 중간 카운터도 같은 overlay 경로로 보여서 poison 두 걸음은 `Ataho 독 2/4`, paralysis 두 이동은 `Ataho 마비 2/3` 렌더 스냅샷을 남긴다. `tools/verify_candidate_movement_browser.py` 는 8013 기준 movement smoke 에서 `statusFeedback=field-status-feedback:Ataho 독 -2 HP 34`, `statusFeedback=field-status-feedback:Ataho 마비 이동 실패`, partial continue 의 `statusFeedback=field-status-feedback:Ataho 독 2/4`, `statusFeedback=field-status-feedback:Ataho 마비 2/3`, `statusFeedbackRender=True` 를 확인한다. 이는 필드 상태이상 발생과 진행 카운터를 플레이어가 즉시 볼 수 있게 하는 웹 gameplay 피드백이며, 원본 상태 공식/상태 flag/story flag proof 로 승격하지 않는다.
- 2026-06-06 필드 상태이상 치료 stale 피드백 정리: 해독초로 poison/paralysis 를 치료할 때 이전 `field-status-feedback` overlay 가 남지 않도록 `clearFieldStatusFeedbackFor()` 를 추가했다. movement smoke 는 치료 직전에 synthetic stale `Ataho 독 -2 HP 34` / `Ataho 마비 이동 실패` feedback 을 심은 뒤 `statusFeedbackCleared=True`, active feedback count `1->0`, last feedback/render `null` 을 확인한다. 이는 치료 후 화면/HUD/status-menu 에 낡은 상태 표시가 남지 않게 하는 웹 gameplay 정리이며, 원본 상태 공식/상태 flag/story flag proof 로 승격하지 않는다.

- 2026-06-05 테스트 웹 포트 8013 고정: 브라우저 smoke/proxy 확인이 매번 포트 변경으로 흔들리지 않게 README quick start, `tools/verify_runtime_http.py`, 모든 `verify_*_browser.py` 계열 `--base` 기본값을 `http://127.0.0.1:8013` 으로 맞췄다. 테스트 서버는 `python3 -m http.server 8013` 으로 띄우고, 포트가 이미 점유되어 있으면 `fuser -k 8013/tcp` 로 정리한 뒤 같은 포트로 다시 실행한다. 이 변경은 검증 운영 고정이며 completion proof 로 승격하지 않는다.

- 2026-06-05 이벤트 VM partial replay 보강: `out/event_dialogue_blocks_runtime.js` 는 각 indexed dialogue block 에 `vmTrace` 를 포함해 opcode `0x02` cursor/separator, `0x0d` text source, `0x0b` render, `0x35` literal marker 를 브라우저에서 부분 replay 할 수 있게 했다. `0x02` 는 handler `0x0041b771` 근거의 4바이트 cursor/separator trace 로 보존하고, `0x35` 는 실행 순서를 과장하지 않도록 별도 `literalTextEvents` 로 보존하며 현재 526개 `0x02` trace 와 41개 블록/249개 literal payload 가 들어 있다. `web/index.html` 의 `startDialogue()` 는 후보 대사를 열 때 `HWANSE_LAST_EVENT_VM_REPLAY` 에 `vmPartial=True`, `vmFull=False`, 실행 opcode, cursor/separator event, render event, source value, literal event count/sample 을 남기고, 대사 박스 snapshot/진행/완료 자동 저장 evidence 에 `vmDrivenLineCount`, `renderCoverageStatus`, `firstRenderTextSourceValueHex`, `literalTextEventCount` 를 연결한다. `event-dialogue-block-003` 의 대사 기반 린샹 합류도 이 replay 요약을 marker/autosave/progress 로 이어 받아 `vmPartial=True`, `vmRender=7`, `vmLiteral=7`, `vmSource=0x00030000` 을 남긴다. `tools/verify_mobile_browser_controls.py` 는 8013 기준 WebKit smoke 에서 `map4_08n` 의 `event-dialogue-block-005` 가 `vmPartial=True`, `vmFull=False`, `vmOpcodes` 에 `0x02`/`0x0d`/`0x0b` trace 를 남기고, `vmDriven=2/13`, `vmCoverage=partial-render-prefix`, `vmSource=0x00030000` 를 기록하는지 확인한다. 이 보강은 browser event VM implementation 의 일부 opcode trace replay 를 명시한 것이며, route-linked event VM execution, full browser event VM implementation, story flag runtime proof 는 계속 미완료로 유지한다.
- 2026-06-05 이벤트 VM control/display opcode semantics 보강: `out/event_vm_opcode_semantics.*` 는 `0x02` 이후 대사 블록에서 많이 보이는 opcode `0x03`/`0x04`/`0x06`/`0x07`/`0x08`/`0x09`/`0x0a`/`0x0e`/`0x15`/`0x1b`/`0x37` 도 handler table 과 disassembly 에 맞춰 별도 semantics row 로 고정한다. `0x03` 은 `context+0xde` display/font row, `0x04` 는 `context+0xca` timer/state seed, `0x06` 은 input release wait latch, `0x07` 은 object fixed-point x/y, `0x08` 은 mode0 table 또는 mode1 immediate style triplet, `0x09` 는 continuation stack + branch target control-flow, `0x0a` 는 continuation stack return, `0x0e`/`0x15` 는 text cursor/origin relative offset, `0x1b` 는 backing data-bank selector, `0x37` 은 global timer/state seed 로 기록한다. `out/event_dialogue_blocks_runtime.js` 는 이 grounded control/display command 1007개를 `groundedControlEvents` metadata 로 보존하고, `web/index.html` 의 replay summary 는 브라우저-local text layout/input latch 상태에 한해 `groundedControlEffectsExecuted=True` 를 남기지만 `browserEventVmFullImplementation=False` 와 `originalEventVmRuntimeImplemented=False` 를 유지한다. 이 보강은 instruction/operand gap 을 일부 줄이고 웹 대사 UI 일부에 적용하는 handler-grounded evidence 이며, 브라우저는 아직 branch/control-flow 를 원본 VM 처럼 실행하지 않고 route-linked event VM execution/full browser event VM implementation/story flag proof 는 계속 false 로 유지한다.
- 2026-06-06 대사 입력 release latch 보강: `web/index.html` 은 partial event VM replay 의 grounded opcode `0x06` input release wait latch 를 키보드/터치 대사 진행에 적용한다. 실제 `Enter`/`Space` keydown 경로는 `requestDialogueAdvance()` 를 거쳐 첫 입력만 한 줄 진행하고, keyup 전 반복 keydown 은 `repeatBlocked=True` 로 차단하며, keyup 뒤 다음 keydown 만 다시 진행한다. Canvas 대사 터치는 `pointerdown` 에서 한 줄만 진행하고 `pointerup` 에서 latch 를 해제하며, 모바일 A 버튼은 `pointerup` 진행 뒤 latch 를 즉시 해제한다. 내부 검증/자동 진행 루프가 쓰는 `advanceDialogue()` 는 그대로 두어 브라우저 smoke 와 runtime menu 흐름을 깨지 않게 했다. `tools/verify_candidate_dialogue_progress_browser.py` 는 `event-dialogue-block-005` 에서 canvas `releaseCleared=True`, keyboard `firstAdvanced=True`, `repeatBlocked=True`, `releaseCleared=True`, `secondAdvancedAfterRelease=True`, `browserDialogueInputWaitLatchImplemented=True`, `originalEventVmRuntimeImplemented=False` 를 확인한다. 이는 grounded control opcode 일부를 웹 gameplay 입력감에 적용한 보강이며, 원본 event VM 전체 실행, route-linked event VM execution, story flag proof 로 승격하지 않는다.
- 2026-06-06 대사 object position focus 보강: partial event VM replay 의 grounded opcode `0x07` object fixed-position metadata 를 대사 중 필드 화면 focus marker 로 표시한다. `event-dialogue-block-005` 는 handler-grounded position `0x0045ee3c -> 144,248` 을 갖고, `drawDialogueVmObjectFocusMarker()` 는 이 좌표를 작은 marker 로 렌더링하며 `HWANSE_LAST_DIALOGUE_OBJECT_FOCUS_RENDER` 에 `rendered=True`, `xy=144,248`, `browserEventVmObjectPositionFocusImplemented=True`, `originalObjectVmRuntimeImplemented=False` 를 남긴다. `tools/verify_candidate_dialogue_progress_browser.py` 와 completion audit verifier 는 이 marker evidence 를 요구한다. 이는 grounded object-position metadata 를 웹 대사 UX 에 반영한 것이며, 원본 object VM 실행, NPC 스크립트 실행, route-linked event VM execution, story flag proof 로 승격하지 않는다.
- 2026-06-06 대사 display style/timer 보강: `web/index.html` 은 grounded opcode `0x03` display/font row, `0x08` display style triplet, `0x04`/`0x37` timer seed 를 `dialogueVmDisplayStyleRenderState()` 로 묶어 대사창 header/text 색, font 크기, line height 에 적용하고 `HWANSE_LAST_DIALOGUE_DISPLAY_STYLE_RENDER` 및 dialogue snapshot 에 남긴다. `event-dialogue-block-005` 는 default style(`fontRow=0`, `styleTableIndex=0`, `timerSeed=0`) 을 확인하고, 별도 browser probe 는 `event-dialogue-block-029` 의 비기본 style(`fontRow=2`, `styleTableIndex=1`, `styleName=emphasis`, `displayTimerRaw=2880`) 을 확인한다. `tools/verify_candidate_dialogue_progress_browser.py`, `tools/verify_web_assets.py`, completion audit verifier 는 `browserEventVmDisplayStyleImplemented=True` 와 `browserEventVmDisplayTimerStateImplemented=True` 를 요구한다. 이는 handler-grounded display state 를 웹 대사 렌더링에 적용한 것이며, 원본 event VM branch/control-flow 실행, route-linked event VM execution, story flag proof 로 승격하지 않는다.
- 2026-06-06 대사 cursor-relative layout 보강: `web/index.html` 은 grounded opcode `0x0e` 의 `set-cursor-relative-to-text-origin` 이벤트를 `cursorRelativeEvents` 로 실행 상태에 반영하고, render command VA 기준 가장 가까운 이전 cursor event 를 `vmRenderEvent.cursorLayout` 으로 연결한다. 대사창은 해당 cursor layout 이 있는 줄에서 relative x/y 를 텍스트 위치에 적용하고 `browserEventVmCursorRelativeLayoutImplemented=True` 를 snapshot 에 남긴다. `event-dialogue-block-028` probe 는 `cursorRelativeCount=37`, `lineLayoutCount=20`, 현재 줄 `기본기`, `cursorRaw=24,96`, `cursorRelative=24,96` 을 확인한다. 이는 EXE handler-grounded cursor layout 을 웹 렌더링에 일부 적용한 것이며, 원본 event VM branch/control-flow 실행, route-linked event VM execution, story flag proof 로 승격하지 않는다.

- 2026-06-06 대사 branch/data-bank control-flow 요약 보강: `web/index.html` 은 grounded opcode `0x09` branch call, `0x0a` branch return, `0x1b` data-bank selector 를 partial replay 상태에 요약한다. `event-dialogue-block-005` 는 `calls=4`, `returns=1`, `maxDepth=4`, `finalDepth=4`, `underflowReturns=1`, `firstTarget=0x0045ee2c`, `firstContinuation=0x0045ee64`, `dataBank=0`, `dataBankSelects=1` 을 dialogue snapshot/progress/autosave evidence 로 남기고, `tools/verify_candidate_dialogue_progress_browser.py`, `tools/verify_web_assets.py`, completion audit verifier 는 `browserEventVmControlFlowSummaryImplemented=True` 를 요구한다. 이는 브라우저-local metadata summary 이며 branch target 을 실제 원본 VM 처럼 jump/return 실행하지 않으므로 route-linked event VM execution, full browser event VM implementation, story flag proof 로 승격하지 않는다.

- 2026-06-05 후보 오브젝트 연결 대사 VM replay 보강: `web/index.html` 의 후보 대사 진행/완료/자동 저장 `vmReplay` payload 를 `eventVmReplaySummaryForBlock()` 기준으로 통일해 `blockId`, `vmPartial=True`, `vmFull=False`, render/literal/source evidence 를 보존한다. `tools/verify_candidate_event_object_browser.py` 는 `map2_03l` 조사 follow-up 대사 `event-dialogue-block-004` 와 남은 연결 후보 `event-dialogue-block-032,041` 이 완료될 때 progress/autosave/smoke snapshot 에 partial replay 를 남기는지 확인한다. 새 `out/candidate_event_object_browser_smoke.*` evidence 는 `vmBlocks=event-dialogue-block-004 vmPartial=True vmFull=False vmRender=6 vmLiteral=9 vmSource=0x00030000` 및 전체 완료 `vmBlocks=event-dialogue-block-004,event-dialogue-block-032,event-dialogue-block-041 vmPartial=True,True,True vmFull=False,False,False vmRender=6,3,5 vmLiteral=9,4,8 vmSource=0x00030000,0x00030000,0x00030000` 를 남긴다. 이 보강도 원본 NPC/object script 실행 proof 나 full event VM 구현으로 승격하지 않고 `originalLinkedDialogueRuntimeImplemented=False`, `originalEventObjectRuntimeImplemented=False`, `achieved=False` 를 유지한다.

- 2026-06-05 후보 전투 VM replay 증거 보강: source-backed 후보 전투 시작/승리 저장도 선택된 event dialogue block 의 partial replay summary 를 보존한다. `web/index.html` 은 `ensureBattleData()` 에서 event dialogue block runtime 도 함께 준비하고, `battlePrototypeSummary()`, `battle-start` 진행 기록, `battle-victory` 진행 기록, 승리 auto-save marker 에 `vmReplay` 를 싣는다. `tools/verify_candidate_battle_browser.py` 는 `map1_02b` 의 `event-dialogue-block-015:btl_b1` family/action/completed battle 에 대해 `vmBlocks=event-dialogue-block-015 vmPartial=True vmFull=False vmRender=5 vmLiteral=2 vmSource=0x00030000` 를 확인하고, requested `map2_07e` 전투 `event-dialogue-block-041:btl_e1` 에 대해서는 `vmBlocks=event-dialogue-block-041 vmPartial=True vmFull=False vmRender=5 vmLiteral=8 vmSource=0x00030000` 를 확인한다. 이 보강은 후보 전투 gameplay loop 의 source block 추적성을 높이는 것이며, 원본 event-driven battle entry, enemy row, reward table, combat formula, story flag proof 로 승격하지 않는다.
- 2026-06-08 런타임 전투 선택 메뉴 보강: `web/index.html` 런타임 메뉴에 `전투 선택 N` 을 추가해 현재 맵/family 의 source-backed battle candidates 를 `battle-candidate` 하위 메뉴로 고를 수 있게 했다. `tools/verify_candidate_battle_browser.py` 는 8013 기준 `map2_14j` 에서 `event-dialogue-block-010:btl_j1` 을 메뉴로 선택해 `btl_j1` 전투가 시작되고 `enemyName=황야 괴수`, `enemySprite=zkb_hyr.cns`, `battleStartFeedback=battle-start-feedback:전투 시작 btl_j1`, `source=prototype-battle-candidate-menu` 를 남기는지 확인한다. 이는 실제 웹 gameplay 선택면 보강이며, 원본 event-driven battle entry, original enemy row binding, story flag proof 로 승격하지 않는다.
- 2026-06-09 전투 action handler provenance 보강: `tools/summarize_battle_action_handler_context.py` 는 event/object VM opcode `0x36` handler `0x0041ff44` 가 `0x004d24ac` / `atahoActions` text table(`정권`, `돌려차기`, `던지기`, `마시기`)을 참조한다는 근거를 `out/battle_action_handler_context.*` 로 분리한다. 이 값은 원본 전투 action/UI text handler 근거지만 현재 dialogue storage scan 에 opcode `0x36` command 는 0개이고, battle-entry dispatch path, enemy row, formation, reward table, combat formula 는 여전히 증명되지 않았다. `out/original_battle_data_gap.*`, `out/event_battle_gap_audit.*`, `out/completion_audit.*` 는 이 handler 근거를 함께 노출하면서도 extracted boss*/z* sprite PNG 65개와 EXE-nearest battle review candidate 21개를 원본 enemy row/stat/reward proof 로 승격하지 않는다. `tools/verify_web_assets.py` 는 `battleActionHandlerStatus=battle-action-handler-grounded-entry-dispatch-missing`, `battleActionHandlerGrounded=True`, `battleActionOpcode=0x36`, `battleActionHandler=0x0041ff44`, `battleActionTable=0x004d24ac`, `battleActionOpcodeInDialogueStorage=False`, `battleActionEntryDispatchProof=False` 를 검사한다.
- 2026-06-05 전투 승리 보상 overlay 보강: 후보 전투 승리 직후 이미 계산된 prototype money/EXP/drop/level-up 결과를 전투 로그에만 두지 않고 1.4초짜리 화면 overlay 로 보여준다. `web/index.html` 은 `HWANSE_BATTLE_REWARD_EFFECT_LOG`, `HWANSE_LAST_BATTLE_REWARD_EFFECT`, `HWANSE_LAST_BATTLE_REWARD_EFFECT_RENDER` 를 남기며, 완료 smoke 는 `rewardEffectSource=battle-victory`, `rewardEffectDuration=1400`, `rewardEffectLines=소지금 +...,경험치 +7,약초 +1,Ataho Lv2`, `rewardEffectRender=True` 를 확인한다. 이 피드백은 browser-local prototype reward/level-up 결과를 플레이 화면에서 바로 보이게 하는 UX 보강이며, 원본 reward table/drop table/level formula proof 로 승격하지 않는다.
- 2026-06-07 전투 승리 보상 overlay WLK sound marker 보강: 후보 전투 보상 overlay 도 승리 직후 재생되는 `victory` WLK 사운드(`../extract_wlk/12.wav`)를 같은 reward effect entry 에 연결한다. `recordBattleRewardEffect()` log/render snapshot 은 이제 `battleRewardSound=victory`, `battleRewardSoundSrc=../extract_wlk/12.wav`, `battleRewardSoundPlayed=True` 를 남기고, `tools/verify_candidate_battle_browser.py` 는 완료 smoke 에서 `rewardEffectSound=victory:../extract_wlk/12.wav:True` 를 확인한다. `tools/verify_web_assets.py` 는 candidate battle smoke JSON/MD, completion snapshot, audit evidence 에서 같은 marker 를 요구한다. 이는 전투 승리 보상 표시가 overlay, 보상 상태, WLK 승리 효과음을 같은 gameplay feedback 단위로 남기게 하는 웹 구현 보강이며, 원본 reward table/DirectSound timing/story flag proof 로 승격하지 않는다.
- 2026-06-06 전투 보상 드롭 EXE item text-table provenance 보강: 후보 전투 승리 드롭도 도구 사용과 같은 `items` text table 근거를 보존한다. `grantBattlePrototypeItemDrop()` 은 `prototype-enemy-drop` 결과에 `itemNameSource=exe-text-table-items` 와 `itemTextTable*` fields 를 붙이고, `battle-victory`/`field-encounter-victory` 진행 detail, 승리 auto-save marker, reward overlay log/render 가 같은 값을 보존한다. WebKit battle smoke 는 `btl_b1` 약초 드롭이 `items[0]` / `0x0048b984 -> 0x0048ba7c`, requested `btl_e1` 해독초 드롭이 `items[1]` / `0x0048b98c -> 0x0048ba8e` 에서 온다는 `enemyDropItemTextRef`/`dropItemTextRef`/`rewardDropItemTextRef` evidence 를 확인한다. 이는 browser-local prototype reward/drop 이름 provenance 를 EXE item text table 에 연결하는 보강이며, 원본 reward/drop table, enemy row, story flag runtime proof 로 승격하지 않는다.
- 2026-06-06 오브젝트 연결 전투 드롭 provenance 검증 보강: `map2_03l` 의 조사 -> 연결 대사 -> 전투 체인도 같은 `grantBattlePrototypeItemDrop()` 경로를 타므로, `tools/verify_candidate_event_object_browser.py` 가 linked battle action/victory/chain 에서 해독초 드롭의 `items[1]` / `0x0048b98c -> 0x0048ba8e` provenance 를 확인하게 했다. Smoke 산출물은 `enemyDropItemTextRef`, `dropItemTextRef`, `rewardDropItemTextRef`, `rewardRenderDropItemTextRef`, chain 의 `stepDropItemTextRefs`/`rewardDropItemTextRefs`/`rewardRenderDropItemTextRefs` 를 남긴다. 이는 오브젝트 연결 전투 보상 루프까지 EXE item text table provenance 가 이어지는지 검증하는 보강이며, 원본 event-driven battle entry, reward/drop table, story flag runtime proof 로 승격하지 않는다.
- 2026-06-05 필드 전투 탐색 진행 overlay 보강: 필드 전투 탐색 모드에서 한 칸 이동해 step counter 가 증가하면 HUD 의 `전투 1/6` 뿐 아니라 플레이 화면 위에 `전투 탐색 1/6` overlay 를 잠시 표시한다. threshold 도달 직전에는 같은 경로가 `전투 발생 <btl>` marker 를 남긴다. `web/index.html` 은 `HWANSE_FIELD_ENCOUNTER_FEEDBACK_LOG`, `HWANSE_LAST_FIELD_ENCOUNTER_FEEDBACK`, `HWANSE_FIELD_ENCOUNTER_FEEDBACK_RENDER`, `HWANSE_LAST_FIELD_ENCOUNTER_FEEDBACK_RENDER` 를 노출하고, `tools/verify_title_start_browser.py` 는 8013 기준 title `전투 탐색 시작` smoke 의 첫 이동 자동 저장에서 `encounterFeedback=field-encounter-step-feedback:전투 탐색 1/6`, `encounterFeedbackRender=True`, `durationMs=900`, `browserFieldEncounterFeedbackImplemented=True` 를 확인한다. 이는 필드 전투 탐색 진행이 저장/HUD 에만 묻히지 않고 즉시 보이게 하는 웹 gameplay UX 보강이며, 원본 encounter table/runtime/story flag proof 로 승격하지 않는다.
- 2026-06-06 필드 전투 탐색 mode overlay 보강: 필드 전투 탐색을 켜거나 끄는 순간도 step overlay 와 같은 `recordFieldEncounterFeedback()` 경로를 사용해 플레이 화면 위에 잠시 표시한다. 제목 `전투 탐색 시작` 경로는 `modeFeedback=field-encounter-enable-feedback:전투 탐색 켬 0/6`, `modeFeedbackRender=True` 를 남기고, 런타임 메뉴에서 `전투 탐색 끄기 1/6` 을 실행하면 `disableFeedback=field-encounter-disable-feedback:전투 탐색 끔 1/6`, `disableFeedbackRender=True` 를 남긴다. 이 marker 는 `HWANSE_LAST_FIELD_ENCOUNTER_MODE.modeFeedback` 과 mode auto-save detail 에도 보존되며, 원본 encounter table/runtime/story flag proof 로 승격하지 않는다.
- 2026-06-07 필드 전투 탐색 WLK step sound marker 보강: `recordFieldEncounterFeedback()` 은 이제 실제 이동 step 때 이미 재생된 `step` WLK 사운드(`../extract_wlk/00.wav`)를 탐색 step/trigger overlay 에 연결해 `fieldEncounterSound=step`, `fieldEncounterSoundSrc=../extract_wlk/00.wav`, `fieldEncounterSoundPlayed=True` 를 log/render snapshot 에 남긴다. `tools/verify_title_start_browser.py` 는 `전투 탐색 1/6` step overlay 의 `encounterFeedbackSound=step:../extract_wlk/00.wav:True` 를 확인하고, `tools/verify_candidate_battle_browser.py` 는 6/6 trigger 의 `전투 발생 btl_b1` overlay 에도 같은 marker 가 붙는지 확인한다. 이는 필드 전투 탐색 진행/발생이 HUD, overlay, 실제 걷기 WLK 효과음을 같은 gameplay feedback 단위로 남기도록 하는 웹 구현 보강이며, 원본 encounter table/DirectSound timing/story flag proof 로 승격하지 않는다.
- 2026-06-07 필드 전투 완료 알림 overlay WLK sound marker 보강: 반복 가능한 `fieldEncounter` 완료 목표의 `완료 알림 확인` 도 `recordFieldEncounterFeedback()` 경로를 통해 `필드 전투 완료 1/1` overlay 를 렌더하고 이미 재생한 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 log/render snapshot 에 연결한다. 8013 기준 `tools/verify_candidate_battle_browser.py` 는 직접 필드 전투 승리 직후와 title `이어하기 map1_02b 11,12 전투` 복원 뒤 모두에서 `fieldNoticeFeedback=field-encounter-completion-notice-feedback:필드 전투 완료 1/1`, `fieldNoticeFeedbackRender=True`, `fieldNoticeSound=menuConfirm:../extract_wlk/04.wav:True` 를 확인한다. 이는 필드 전투 완료 확인이 목표 알림, overlay, WLK 확인음을 같은 gameplay feedback 단위로 남기도록 하는 웹 구현 보강이며, 원본 encounter table/runtime/reward/drop/story flag proof 로 승격하지 않는다.
- 2026-06-06 임시 저장/불러오기 overlay 보강: 명시적인 `임시 저장`, title `이어하기`, `임시 불러오기` 경로도 browser-local 저장/복원 결과를 캔버스 위에 잠시 표시한다. `web/index.html` 은 `HWANSE_RUNTIME_SAVE_FEEDBACK_LOG`, `HWANSE_LAST_RUNTIME_SAVE_FEEDBACK`, `HWANSE_RUNTIME_SAVE_FEEDBACK_RENDER`, `HWANSE_LAST_RUNTIME_SAVE_FEEDBACK_RENDER` 를 노출하고, 8013 기준 title smoke 는 새 게임 수동 저장에서 `quickSaveFeedback=title-start-smoke-quick-save-feedback:임시 저장 map1_02b 11,12`, `quickSaveFeedbackRender=True`, title 이어하기 복원에서 `quickLoadFeedback=title-continue-feedback:임시 불러오기 map1_02b 11,12`, `quickLoadFeedbackRender=True` 를 확인한다. 이는 웹-local debug save/load 조작이 성공했는지 즉시 보이게 하는 gameplay UX 보강이며, 원본 save point event/runtime/story flag proof 로 승격하지 않는다.
- 2026-06-07 임시 저장/불러오기 WLK menuConfirm sound marker 보강: `recordRuntimeSaveFeedback()` 은 이제 명시적인 `임시 저장`, title `이어하기`, `임시 불러오기` overlay log/render snapshot 에 `runtimeSaveSound=menuConfirm`, `runtimeSaveSoundSrc=../extract_wlk/04.wav`, `runtimeSaveSoundPlayed=True` 를 남긴다. 런타임 메뉴와 title 메뉴는 이미 재생된 메뉴 선택 sound entry 를 넘겨 중복 재생하지 않고, 상단 quick-save/quick-load 버튼처럼 별도 확인음이 없던 feedback 경로는 `menuConfirm` 을 한 번 재생해 같은 marker 로 연결한다. 8013 기준 title smoke 는 `quickSaveFeedbackSound=menuConfirm:../extract_wlk/04.wav:True` 와 `quickLoadFeedbackSound=menuConfirm:../extract_wlk/04.wav:True` 를 확인하고, `tools/verify_web_assets.py` 와 `tools/summarize_completion_audit.py` 는 smoke JSON/MD 및 completion audit evidence 에서 같은 marker 를 요구한다. 이는 browser-local 저장/불러오기 조작이 overlay, 복원 상태, WLK 확인음을 같은 gameplay feedback 단위로 남기게 하는 웹 구현 보강이며, 원본 save point event/DirectSound timing/story flag proof 로 승격하지 않는다.
- 2026-06-06 맵 이동 overlay 보강: confirmed 전환과 routeAssist 후보 전환이 자동 저장/암전 효과로만 지나가지 않게, 이동 직후 `맵 이동 map1_02b -> map1_01a` 또는 `후보 이동 map1_01a -> map2_02d` overlay 를 1초 동안 표시한다. `web/index.html` 은 `HWANSE_MAP_TRANSITION_FEEDBACK_LOG`, `HWANSE_LAST_MAP_TRANSITION_FEEDBACK`, `HWANSE_MAP_TRANSITION_FEEDBACK_RENDER`, `HWANSE_LAST_MAP_TRANSITION_FEEDBACK_RENDER` 를 노출하고, 8013 기준 title smoke 는 입력 전환에서 `transitionFeedback=map-transition-feedback:맵 이동 map1_02b -> map1_01a`, `transitionFeedback=route-candidate-feedback:후보 이동 map1_01a -> map2_02d`, `transitionFeedbackRender=True` 를 확인한다. 이는 웹 gameplay 에서 이동 결과를 즉시 확인하게 하는 UX 보강이며, `route-candidate` 는 계속 browser-local 후보 경로로 남고 원본 route promotion, 원본 transition text runtime, story flag proof 로 승격하지 않는다.
- 2026-06-06 맵 이동 WLK transition sound 증거 보강: confirmed 전환과 routeAssist 후보 전환 완료 시 이미 재생하던 추출 WLK `transition` 효과음 `extract_wlk/07.wav` 를 `HWANSE_LAST_TRANSITION_EFFECT` 및 map transition feedback log/render 에도 보존한다. 8013 기준 title smoke 는 실제 `ArrowUp` 입력으로 `map1_02b -> map1_01a` confirmed 전환과 `map1_01a -> map2_02d` routeAssist 후보 전환을 실행한 뒤 각각 `confirmedTransitionSound=transition:../extract_wlk/07.wav:True`, `candidateTransitionSound=transition:../extract_wlk/07.wav:True` 및 sound count 1회를 확인한다. 이 보강은 웹 gameplay 맵 이동 결과를 화면/저장/효과음 이벤트로 함께 관찰하게 만드는 것이며, 원본 DirectSound mixing/timing, 원본 transition runtime, route promotion, story flag proof 로 승격하지 않는다.
- 2026-06-05 필드 전투 발생 overlay 렌더 보강: 위 feedback 경로를 battle scene 에도 연결해 6/6 이동으로 전투가 열리는 순간 `전투 발생 btl_b1` overlay 가 전투 화면 위에 실제로 남도록 했다. `tools/verify_candidate_battle_browser.py` 는 8013 기준 `encounter=1` smoke 에서 실제 방향키 이동 6회 후 `encounterFeedback=field-encounter-trigger-feedback:전투 발생 btl_b1`, `encounterFeedbackRender=True`, `triggered=True`, `stepCount=6`, `durationMs=900`, `browserFieldEncounterFeedbackImplemented=True` 를 확인한다. 이 변경은 필드 전투 발생 순간을 전투 시작/승리/이어하기 검증과 같은 플레이 루프에 붙이는 웹 gameplay 보강이며, 원본 encounter table/runtime/story flag proof 로 승격하지 않는다.
- 2026-06-05 대사 완료 overlay 보강: 후보 대사를 끝까지 넘겨 `dialogue-complete` 진행 기록이 생기는 순간, 자동 저장과 버튼 갱신만 남기지 않고 플레이 화면 위에 `대사 완료 1/2` overlay 를 1초 동안 표시한다. `web/index.html` 은 `HWANSE_DIALOGUE_COMPLETION_FEEDBACK_LOG`, `HWANSE_LAST_DIALOGUE_COMPLETION_FEEDBACK`, `HWANSE_DIALOGUE_COMPLETION_FEEDBACK_RENDER`, `HWANSE_LAST_DIALOGUE_COMPLETION_FEEDBACK_RENDER` 를 노출하고, `tools/verify_candidate_dialogue_progress_browser.py` 는 8013 기준 `map4_08n` 완료 smoke 에서 `dialogueFeedback=dialogue-completion-feedback:대사 완료 1/2`, `dialogueFeedbackRender=True`, `durationMs=1000`, `browserDialogueCompletionFeedbackImplemented=True`, `nextBlockId=event-dialogue-block-026` 을 확인한다. 이 피드백은 후보 대사 완료가 저장/메뉴 상태에만 묻히지 않고 즉시 보이게 하는 웹 gameplay UX 보강이며, 원본 event VM/runtime/story flag proof 로 승격하지 않고 `originalEventVmRuntimeImplemented=False`, `originalStoryFlagRuntimeImplemented=False` 를 유지한다.
- 2026-06-06 대사 WLK sound marker 보강: `startDialogue()` 는 대사 열기 효과음을 `dialogue-open-sound`, `advanceDialogue()` 는 각 줄 넘김 효과음을 `dialogue-advance-sound` marker 로 기록하고 둘 다 `../extract_wlk/01.wav` provenance 를 보존한다. `tools/verify_candidate_dialogue_progress_browser.py` 는 8013 기준 `map4_08n` 완료 smoke 에서 첫 열기/B취소/재오픈이 `dialogueOpenSoundCount=2`, `dialogueOpenSoundSrc=../extract_wlk/01.wav` 를 남기는지, canvas pointer 첫 advance 가 `dialogueSoundCount=1`, `advanceSound=dialogue-advance-sound:0->1` 을 남기는지, keyboard 첫 advance/repeat/둘째 advance 가 `soundFirst=2`, `soundRepeat=2`, `soundSecond=3` 으로 repeat keydown 에서 소리가 중복 증가하지 않는지, 전체 13줄 완료가 `dialogueAdvanceSoundCount=13`, `dialogueAdvanceSoundSrc=../extract_wlk/01.wav` 를 남기는지 확인한다. 이 보강은 대사 열기와 진행이 화면과 입력 latch 뿐 아니라 추출 WLK 효과음 이벤트로도 관찰 가능하게 하는 browser-local gameplay 증거이며, 원본 DirectSound mixing/timing, full event VM runtime, story flag proof 로 승격하지 않고 `originalEventVmRuntimeImplemented=False`, `originalStoryFlagRuntimeImplemented=False` 를 유지한다.
- 2026-06-07 대사 완료 overlay WLK dialogue sound marker 보강: `recordDialogueCompletionFeedback()` 은 이제 마지막 대사 진행에서 이미 재생된 `dialogue` WLK 사운드(`../extract_wlk/01.wav`)를 completion overlay 에 연결해 `dialogueCompletionSound=dialogue`, `dialogueCompletionSoundSrc=../extract_wlk/01.wav`, `dialogueCompletionSoundPlayed=True` 를 log/render snapshot 에 남긴다. `advanceDialogue()` 는 마지막 줄에서 얻은 sound entry 를 `recordDialogueCompleteProgress()` 로 넘기므로 완료 순간에 소리를 중복 재생하지 않는다. 8013 기준 `tools/verify_candidate_dialogue_progress_browser.py` 는 `dialogueFeedbackSound=dialogue:../extract_wlk/01.wav:True` 를 확인하고, `tools/verify_web_assets.py` 와 `tools/summarize_completion_audit.py` 는 candidate dialogue smoke JSON/MD 및 completion audit event evidence 에 같은 marker 를 요구한다. 이는 대사 완료가 자동 저장, overlay, 마지막 대사 WLK 효과음을 같은 gameplay feedback 단위로 남기게 하는 웹 구현 보강이며, 원본 event VM runtime/DirectSound timing/story flag proof 로 승격하지 않는다.
- 2026-06-07 대사 완료 알림 overlay/WLK sound 보강: 완료된 후보 대사의 `목표`/완료 알림 경로가 완료 대화만 여는 데서 끝나지 않게 `dialogue-completion-notice-feedback` overlay 를 맵 화면 위에 표시하고 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 남기게 했다. 실제 대사를 끝내는 순간의 `dialogue-completion-feedback` 은 기존처럼 마지막 대사 sound 를 사용하고, 복원 후 완료 알림 확인 조작만 별도 notice feedback 으로 구분한다. `tools/verify_candidate_dialogue_progress_browser.py` 는 8013 기준 direct all-complete 상태와 title `이어하기 map4_08n` 복원 상태 양쪽에서 `noticeFeedback=dialogue-completion-notice-feedback:대사 완료 2/2`, `noticeFeedbackRender=True`, `noticeFeedbackSound=menuConfirm:../extract_wlk/04.wav:True` 를 요구하고, `tools/verify_web_assets.py`/`tools/summarize_completion_audit.py` 도 같은 marker 를 completion audit evidence 로 보존한다. 이는 완료된 대사 확인 조작을 실제 플레이 화면/효과음으로 보이게 하는 UX 보강이며, 원본 event VM runtime, story flag, DirectSound timing proof 로 승격하지 않는다.
- 2026-06-08 런타임 대사 선택 메뉴 보강: `web/index.html` 런타임 메뉴에 `대사 선택 N` 을 추가해 현재 맵의 대사 후보를 `dialogue-candidate` 하위 메뉴에서 직접 고를 수 있게 했다. `tools/verify_candidate_dialogue_progress_browser.py` 는 8013 기준 `map4_08n` 에서 `event-dialogue-block-026` 을 선택해 첫 줄 `스마슈`, `lineCount=14`, `dialogueOpenSound=dialogue-open-sound:../extract_wlk/01.wav`, `source=prototype-dialogue-candidate-menu`, `vmPartial=True`, `vmFull=False` 를 확인한다. 이는 실제 웹 gameplay 선택면 보강이며, 원본 event VM dispatch, route-linked story flag mutation proof 로 승격하지 않는다.

- 2026-06-04 대사/동료 합류 자동 저장 보강: 후보 대사를 끝까지 넘겨 `dialogue-complete` 진행 기록이 생기는 즉시 `autoSavePrototypeRuntime("dialogue-complete")` 로 browser-local 임시 저장을 갱신하고 `HWANSE_LAST_DIALOGUE_COMPLETE_AUTO_SAVE` 를 남기게 했다. `joinPrototypePartyMember()` 도 실제 합류가 생긴 직후 `prototype-party-join` 자동 저장을 수행하며, 대사 기반 합류(`event-dialogue-block-003`)는 모든 합류 처리 뒤 `dialogue-party-join` 자동 저장 marker 를 남긴다. `tools/verify_candidate_dialogue_progress_browser.py` 와 `tools/verify_candidate_party_join_browser.py` 는 이제 테스트 코드에서 직접 `quickSaveRuntime()` 을 호출하지 않고, `autoSaved=True`, `autoSource=dialogue-complete|prototype-party-join|dialogue-party-join`, 저장 payload 의 맵/좌표/진행 기록/수동 파티 상태, 타이틀 `이어하기` 복원을 확인한다. 이 변경은 실제 플레이에서 대화 완료와 동료 합류 뒤 저장을 놓치지 않게 하는 웹 gameplay 보강이며, 원본 event VM/동료 합류 이벤트/story flag runtime proof 로 승격하지 않는다.

- 2026-06-04 장비/상점 변경 자동 저장 보강: prototype 장비 변경, 상점 구매, 상점 판매도 상태 변경 직후 `autoSavePrototypeRuntime()` 으로 browser-local 임시 저장을 갱신하게 했다. `equipPrototypeItem()` 은 `equipment-prototype` 진행 기록과 함께 `HWANSE_LAST_EQUIPMENT_CHANGE_AUTO_SAVE` 를 남기고, `buyShopPrototypeItem()`/`sellShopPrototypeItem()` 은 각각 `shop-buy-prototype`/`shop-sell-prototype` 자동 저장 marker 를 남긴다. `tools/verify_candidate_equipment_menu_browser.py` 와 `tools/verify_candidate_shop_menu_browser.py` 는 테스트 코드의 수동 `quickSaveRuntime()` 호출 없이 `autoSaved=True`, `autoSource=equipment-prototype|shop-buy-prototype|shop-sell-prototype`, 저장 payload 의 맵/좌표/runtimeState 장착 슬롯/소지금/아이템 수량/진행 기록, 그리고 타이틀 `이어하기` 복원을 확인한다. 이 변경은 실제 플레이에서 장비와 상점 조작 뒤 변경 사항이 끊기지 않게 하는 웹 gameplay 보강이며, savedat 장비 offset, 원본 상점 가격/재고, 원본 money mutation/story flag proof 로 승격하지 않는다.

- 2026-06-04 도구 사용 자동 저장 보강: 맵 메뉴에서 prototype 아이템 효과를 적용하는 `useInventoryItem()` 도 `item-use-prototype` 진행 기록 직후 자동 저장을 수행한다. `HWANSE_LAST_INVENTORY_ITEM_USE_AUTO_SAVE` 는 저장 payload 의 맵/좌표/runtimeState HP/아이템 수량/진행 기록과 `prototypeItemUseImplemented=True`, `originalItemEffectFormulaImplemented=False`, `originalStoryFlagRuntimeImplemented=False` 를 남긴다. `tools/verify_title_start_browser.py` 는 새 게임 `map1_02b@11,12` 에서 Ataho HP 24, 약초 1개 상태를 만든 뒤 약초 사용으로 HP 36/약초 0이 되고, 테스트 코드의 수동 `quickSaveRuntime()` 없이 `autoSource=item-use-prototype` 저장을 불러와 같은 상태와 타이틀 `이어하기 map1_02b 11,12` 복원을 확인한다. 이 변경은 웹-local 도구 사용 저장성 개선이며 원본 아이템 효과 공식, 상태 플래그 offset, story flag runtime proof 로 승격하지 않는다.

- 2026-06-04 동료 follower 맵 렌더/trail 검증 보강: `drawParty()` 는 마지막 party render snapshot 을 `HWANSE_LAST_PARTY_RENDER` 에 남겨 실제 맵 렌더 경로가 player 와 joined party sprites 를 어떤 trail 위치에 그렸는지 확인할 수 있게 했다. `tools/verify_candidate_party_join_browser.py` 는 `map1_02b` 에서 린샹/스마슈 합류 뒤 safe movement 7보를 진행해 `party-follower-render source=prototype-party-trail-render`, `followers=party_rinshan,party_smash`, `stepCount=7`, `trailFilledCount=7`, `visibleFollowers=2`, `separateFromPlayer=True`, `actorCollisionEnabled=True`, `actorCollisionBlocked=1` 를 확인한다. 같은 smoke 는 기본 동료 actor overlap collision 이 켜진 상태에서 follower 위치 2개가 overlap block 으로 잡히고, 그중 통행 가능한 follower target 1개가 `canMoveTo=false` 를 만들며 현재 player 위치는 `canMoveTo=true` 로 유지되는지도 확인한다. 이 보강은 동료가 메뉴/전투 상태만이 아니라 필드 맵에서도 따라오는지 검증하는 browser-local gameplay evidence 이며, 원본 companion trail runtime/story flag proof 로 승격하지 않는다.
- 2026-06-05 동료 합류 overlay 보강: prototype 동료 합류가 진행 기록/자동 저장/URL 변경으로만 끝나지 않게, 실제 새 멤버가 추가되는 순간 필드 화면 위에 `동료 합류 린샹` 또는 `동료 합류 스마슈` overlay 를 1.1초 동안 표시한다. `web/index.html` 은 `HWANSE_PARTY_JOIN_FEEDBACK_LOG`, `HWANSE_LAST_PARTY_JOIN_FEEDBACK`, `HWANSE_PARTY_JOIN_FEEDBACK_RENDER`, `HWANSE_LAST_PARTY_JOIN_FEEDBACK_RENDER` 를 노출하고, `tools/verify_candidate_party_join_browser.py` 는 8013 기준 메뉴 합류 경로에서 `joinFeedback=party-join-feedback:동료 합류 스마슈`, `joinFeedbackRender=True`, `durationMs=1100`, `browserPartyJoinFeedbackImplemented=True` 를 확인한다. 같은 smoke 는 `event-dialogue-block-003` 완독으로 린샹이 합류하는 경로도 `joinFeedback=party-join-feedback:동료 합류 린샹`, `joinFeedbackRender=True`, `joinSource=prototype-dialogue-party-join`, `triggerBlockId=event-dialogue-block-003` 으로 확인한다. 이 피드백은 웹 gameplay 에서 동료 합류 순간을 즉시 보이게 하는 보강이며, 원본 party join event/event VM/story flag proof 로 승격하지 않고 `originalPartyJoinEventImplemented=False`, `originalStoryFlagRuntimeImplemented=False` 를 유지한다.
- 2026-06-07 동료 합류 WLK sound 보강: `recordPartyJoinFeedback()` 은 이제 동료 합류 overlay 를 만들 때 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 재생하고 feedback/render snapshot 에 `partyJoinSound=menuConfirm`, `partyJoinSoundSrc=../extract_wlk/04.wav`, `partyJoinSoundPlayed=True` 를 남긴다. `tools/verify_candidate_party_join_browser.py` 는 8013 기준 메뉴 합류의 `동료 합류 스마슈` 와 `event-dialogue-block-003` 대사 합류의 `동료 합류 린샹` 양쪽에서 이 sound marker 를 요구한다. 이는 합류 조작이 화면 overlay 뿐 아니라 실제 확인 효과음도 동반하게 하는 웹 gameplay UX 보강이며, 원본 party join event/event VM/story flag proof 로 승격하지 않는다.
- 2026-06-05 세이브 후보 완료 overlay 보강: 현재 맵에 직접 연결된 save-point 후보가 prototype 회복/저장을 수행하면 대화와 자동 저장만 남기지 않고 필드 화면 위에 `세이브 완료 1` overlay 를 1.1초 동안 표시한다. `web/index.html` 은 `HWANSE_SAVE_POINT_FEEDBACK_LOG`, `HWANSE_LAST_SAVE_POINT_FEEDBACK`, `HWANSE_SAVE_POINT_FEEDBACK_RENDER`, `HWANSE_LAST_SAVE_POINT_FEEDBACK_RENDER` 를 노출하고, `tools/verify_candidate_save_point_browser.py` 는 8013 기준 `map2_07e` 메뉴 저장과 Enter/A action 저장 양쪽에서 `saveFeedback=save-point-feedback:세이브 완료 1`, `saveFeedbackRender=True`, `durationMs=1100`, `recoveredCount=1`, `curedStatusCount=2`, `browserSavePointFeedbackImplemented=True` 를 확인한다. 이 피드백은 후보 세이브 실행과 회복 결과가 플레이 화면에서 즉시 보이게 하는 웹 gameplay UX 보강이며, 원본 save point event/회복 NPC/event VM/story flag proof 로 승격하지 않고 `originalSavePointRuntimeImplemented=False`, `originalRecoveryEventImplemented=False`, `originalStoryFlagRuntimeImplemented=False` 를 유지한다.
- 2026-06-07 세이브 후보 WLK sound 보강: `recordSavePointFeedback()` 은 이제 현재 맵 save-point 후보가 실제 회복/저장을 완료할 때 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 재생하고 feedback/render snapshot 에 `savePointSound=menuConfirm`, `savePointSoundSrc=../extract_wlk/04.wav`, `savePointSoundPlayed=True` 를 남긴다. `tools/verify_candidate_save_point_browser.py` 는 8013 기준 `map2_07e` 메뉴 저장과 Enter/A action 저장 양쪽에서 overlay, candidate evidence, partial VM replay 와 함께 이 sound marker 를 요구한다. 이 보강은 후보 세이브 조작이 화면 표시뿐 아니라 실제 저장 완료 효과음도 동반하도록 하는 웹 gameplay UX 개선이며, 원본 save point event/runtime/story flag proof 로 승격하지 않는다.
- 2026-06-08 런타임 세이브 선택 메뉴 보강: `web/index.html` 런타임 메뉴에 `세이브 선택 N` 을 추가해 save-point 후보를 `save-point-candidate` 하위 메뉴에서 직접 고를 수 있게 했다. `tools/verify_candidate_save_point_browser.py` 는 8013 기준 `map2_07e` 에서 `event-dialogue-block-033` 을 선택해 `scope=current-map`, `saved=True`, `eligible=True`, `selectionSource=prototype-save-point-candidate-menu`, `saveFeedback=save-point-feedback:세이브 완료 1`, `savePointSound=menuConfirm:../extract_wlk/04.wav:True`, `vmBlocks=event-dialogue-block-033`, `vmPartial=True`, `vmFull=False` 를 확인한다. 이는 실제 웹 gameplay 세이브 후보 선택면 보강이며, 원본 save-point event VM dispatch, recovery event execution, story flag mutation proof 로 승격하지 않는다.
- 2026-06-05 후보 오브젝트 조사 overlay 보강: `map2_03l` 의 visible z*.cns 오브젝트 후보를 포인터/조사 버튼/facing-object/near-foot Enter/A 경로로 조사하면, 조사 결과 대사와 자동 저장만 남기지 않고 필드 화면 위에 `조사 완료 3` overlay 를 1.1초 동안 표시한다. `web/index.html` 은 `HWANSE_EVENT_OBJECT_INSPECT_FEEDBACK_LOG`, `HWANSE_LAST_EVENT_OBJECT_INSPECT_FEEDBACK`, `HWANSE_EVENT_OBJECT_INSPECT_FEEDBACK_RENDER`, `HWANSE_LAST_EVENT_OBJECT_INSPECT_FEEDBACK_RENDER` 를 노출하고, `tools/verify_candidate_event_object_browser.py` 는 8013 기준 button/action 조사에서 `inspectFeedback=event-object-inspect-feedback:조사 완료 3`, `inspectFeedbackRender=True`, `durationMs=1100`, `linkedDialogueCount=3`, `browserEventObjectInspectFeedbackImplemented=True` 를 확인한다. 이 피드백은 후보 오브젝트 조사 시작/완료가 플레이 화면에서 즉시 보이게 하는 웹 gameplay UX 보강이며, 원본 NPC/object script/event VM/story flag proof 로 승격하지 않고 `originalLinkedDialogueRuntimeImplemented=False`, `originalEventObjectRuntimeImplemented=False`, `originalStoryFlagRuntimeImplemented=False` 를 유지한다.
- 2026-06-07 후보 오브젝트 조사 WLK sound 보강: `recordEventObjectInspectFeedback()` 은 이제 조사 overlay 를 만들 때 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 재생하고 feedback/render snapshot 에 `inspectSound=menuConfirm`, `inspectSoundSrc=../extract_wlk/04.wav`, `inspectSoundPlayed=True` 를 남긴다. `tools/verify_candidate_event_object_browser.py` 는 8013 기준 `map2_03l` 조사 버튼 경로에서 `조사 완료 3` overlay, linked dialogue summary, follow-up 대사 연결과 함께 이 sound marker 를 요구한다. 이는 오브젝트 조사 조작이 화면 표시와 실제 확인 효과음을 함께 남기도록 하는 웹 gameplay UX 보강이며, 원본 NPC/object script/event VM/story flag proof 로 승격하지 않는다.
- 2026-06-08 런타임 오브젝트 선택 메뉴 보강: `web/index.html` 런타임 메뉴에 `조사 선택 N` 을 추가해 현재 맵의 visible z*.cns 오브젝트 후보를 `object-candidate` 하위 메뉴에서 직접 고를 수 있게 했다. `tools/verify_candidate_event_object_browser.py` 는 8013 기준 `map2_03l` 에서 `zs_rg` 를 선택해 `event-object-candidates:map2_03l` 을 `scope=menu-object`, `assets=zs_rg`, `selectionSource=prototype-object-candidate-menu` 로 열고, `inspectFeedback=event-object-inspect-feedback:조사 완료 1`, `inspectSound=menuConfirm:../extract_wlk/04.wav:True`, `linkedDialogueCount=3` 을 확인한다. 이는 실제 웹 gameplay 선택면 보강이며, 원본 NPC/object VM dispatch, story flag mutation proof 로 승격하지 않는다.
- 2026-06-07 진행 목표 버튼 조사 경로 WLK/프롬프트 보강: `drawActionPrompt()` 과 `activateHotspotAtFoot()` 은 이제 이미 완료된 오브젝트 조사 후보가 같은 타일의 broad 상점 후보보다 먼저 `Enter -> 조사 완료 zg_kni 3개` 를 유지하고 실행하게 한다. `tools/verify_candidate_progress_browser.py` 는 8013 기준 desktop `목표` 버튼으로 `event-object-candidates:map2_03l` 을 여는 경로에서 `quickObjectiveSound=quick-objective-sound:objective-action-button:hotspot-action`, `quickObjectiveSoundSrc=../extract_wlk/04.wav`, `quickObjectiveSoundPlayed=True` 를 요구하고, 조사 완료 후 일반 Enter/A hotspot path 도 `completedHotspotResult=True`, `completedHotspotNotice=event-object-complete:map2_03l` 로 같은 오브젝트 완료 경로를 유지하는지 확인한다. 이는 목표 버튼이 실제 플레이 조작으로 보이고 들리며 완료 프롬프트/실행이 다른 후보에 덮이지 않게 하는 웹 gameplay UX 보강이고, 원본 NPC/object script/event VM/story flag proof 로 승격하지 않는다.
- 2026-06-07 routeAssist waypoint 보강: 후보 진행 모드에서 다음 route source tile 을 필드/overview 화면에 `route-assist-waypoint` marker 로 표시하고 `HWANSE_LAST_ROUTE_ASSIST_WAYPOINT_RENDER` 에 source/target/tile/progress 상태를 남긴다. `tools/verify_route_guide_browser.py` 는 8013 기준 `out/web_playtest_route.html` 의 `routeGoal=map2_18d` 링크가 런타임으로 들어간 뒤 첫 confirmed step `map1_02b -> map1_01a` 의 source tile `11,12` 를 `rendered=True`, `browserRouteAssistWaypointImplemented=True`, `progressKind=map-transition`, `originalRoutePromotionImplemented=False` 로 검증한다. `tools/verify_web_assets.py` 와 `tools/summarize_completion_audit.py` 도 route guide smoke/completion audit 에 같은 waypoint marker 를 요구한다. 이는 후보 경로를 버튼/메뉴만으로 넘기지 않고 실제 필드 화면에서 다음 진행 지점을 보이게 하는 웹 gameplay UX 보강이며, 원본 normal-route promotion, strict hotspot, story flag proof 로 승격하지 않는다.
- 2026-06-07 routeAssist waypoint 클릭/액션 실행 보강: 필드에 표시된 `route-assist-waypoint` marker 가 pointer target 으로 동작하게 해, 마커 위 커서 feedback 과 직접 클릭/tap 으로 `activateRouteNextButton(..., "route-waypoint")` 를 실행한다. 또한 플레이어가 미완료 confirmed waypoint tile 위에 있으면 `Enter -> 다음 map1_01a` 액션 프롬프트를 띄우고, 키보드 Enter/Space 또는 모바일 A 버튼이 `activateRouteNextButton(..., "route-waypoint-action")` 를 실행한다. 성공 시 `HWANSE_LAST_ROUTE_ASSIST_WAYPOINT_ACTION` 은 `route-assist-waypoint-action:map1_02b->map1_01a`, tile `11,12`, `handled=True`, `inputSource=route-waypoint|route-waypoint-action`, `browserRouteAssistWaypointActionImplemented=True` 를 남기고, route-control sound 는 `menuConfirm`, `../extract_wlk/04.wav`, `soundPlayed=True` 로 저장된다. `tools/verify_route_guide_browser.py` 는 8013 기준 route guide 링크로 `map1_02b` 런타임에 들어간 뒤 `Enter -> 다음 map1_01a` prompt 와 Enter 실행, 모바일 A 버튼 실행이 모두 `map1_01a` 에 도착하는지 확인하고, canvas waypoint pointerdown 으로도 `map1_01a`, `routeGoal=map2_18d`, `routeAutoSave=1`, `trialTransitions=routeAssist` 까지 이동하는 경로를 검증한다. `tools/verify_candidate_route_progress_browser.py` 는 완료된 route-candidate source prompt 가 waypoint 액션 프롬프트에 덮이지 않고 기존 `Move/Enter -> 후보 완료 map2_02d ...` 경로를 유지하는지도 다시 확인했다. `tools/verify_web_assets.py` 와 `tools/summarize_completion_audit.py` 도 이 click/action-through/mobile-action evidence 를 요구한다. 이는 후보 경로를 화면 marker 직접 조작과 일반 게임 액션 버튼으로 진행시키는 웹 gameplay UX 보강이며, 원본 normal-route promotion, selected-root execution, story flag proof 로 승격하지 않는다.
- 2026-06-07 routeAssist waypoint 방향 guide 보강: 다음 waypoint 가 현재 발밑이 아닐 때 player foot tile 에서 waypoint 로 점선 guide 를 그리고, HUD 에 `길 다음 <target> <방향> <거리>` 를 표시한다. `HWANSE_LAST_ROUTE_ASSIST_WAYPOINT_GUIDE` 는 `route-assist-waypoint-guide`, source/target, playerTile/tile, distanceX/Y, manhattanDistance, `directionLabel`, `distanceText`, `lineRendered`, `browserRouteAssistWaypointGuideImplemented=True`, `originalRoutePromotionImplemented=False` 를 남긴다. `tools/verify_route_guide_browser.py` 는 8013 기준 `map1_01a@11,11`, `routeGoal=map2_18d` 에서 다음 waypoint `map1_01a -> map2_02d` tile `18,0` 을 `distanceX=7`, `distanceY=-11`, `direction=북동`, `distance=18칸`, `lineRendered=True`, HUD `길 다음 map2_02d 북동 18칸` 으로 검증한다. 이는 후보 routeAssist 를 단순 버튼/마커가 아니라 필드 위에서 따라갈 수 있는 진행 안내로 만드는 웹 gameplay UX 보강이며, 원본 route promotion 또는 strict hotspot proof 로 승격하지 않는다.
- 2026-06-07 routeAssist waypoint 한 칸 안내 이동 보강: routeAssist 목표가 다음 source tile 에서 떨어져 있을 때 `목표`/`G`/모바일 `목` 실행이 즉시 후보 전환을 누르지 않고 `route-waypoint-nudge` 로 waypoint 방향 한 칸 이동을 예약하게 했다. off-tile waypoint marker 클릭/tap 도 같은 nudge 경로를 타므로, 보이는 marker 를 클릭해도 맵을 건너뛰지 않고 한 칸만 이동한다. 현재 waypoint target 이 아닌 반대 방향 route 후보가 발밑에 있을 때는 그 후보 프롬프트보다 `목표 -> 길 안내 map2_02d 북동 18칸` 같은 guide action prompt 를 우선 표시하고, 실제 waypoint target 위에서는 기존 전환 프롬프트를 유지한다. 이동은 기존 필드 이동 루프의 collision, 상태 차단, 발소리 처리 경로를 그대로 타며 `HWANSE_LAST_ROUTE_ASSIST_WAYPOINT_NUDGE` 에 source/target, 시작 tile, nextTile, `inputSource`, `movementQueued=True`, `directionLabel`, `browserRouteAssistWaypointNudgeImplemented=True`, `originalRoutePromotionImplemented=False` 를 남긴다. `tools/verify_route_guide_browser.py` 는 8013 기준 `map1_01a@10,10` 의 nudge prompt, `map1_01a@11,11` 의 marker 클릭 `inputSource=route-waypoint`, 키보드 `G` `inputSource=keyboard`, 상단 `목표` 버튼 `inputSource=objective-action-button`, 모바일 `목` 버튼 `inputSource=virtual-objective-button` 을 확인하고, 모든 nudge 경로가 각각 `11,10` 까지 한 칸 이동하며 waypoint guide 가 `18칸` 에서 `17칸` 으로 줄고 HUD `길 다음 map2_02d 북동 17칸`, field step sound `step` 을 남기는지 검증한다. 같은 smoke 는 키보드 `G` 반복 18보로 `map1_01a@18,0` waypoint 에 실제 도착해 guide 가 `도착` 이 되는지, 도착 뒤 다시 `G` 를 눌러 route-next 로 `map2_02d`, `routeGoal=map2_18d`, `routeAutoSave=1` 로 넘어가는지도 확인한다. 추가로 가까운 시작점 `startTile=16,2` 의 collision-adjusted 위치에서 상단 `목표` 버튼과 모바일 `목` 버튼을 각각 반복 follow control 로 눌러 1보 만에 `map1_01a@18,0` waypoint 에 도착하고, 같은 버튼을 한 번 더 눌러 `route-next` 로 `map2_02d` 에 들어가는 경로까지 검증한다. quick objective 경로는 `keyboard`, `objective-action-button`, `virtual-objective-button` 모두 `menuConfirm` 도 함께 검증한다. waypoint 위에 있을 때의 기존 `route-next`/`route-continuation` 경로는 유지되며, 이는 routeAssist 안내를 실제 조작 루프로 잇는 웹 gameplay 보강이지 원본 normal-route promotion, selected-root execution, story flag proof 로 승격하지 않는다.
- 2026-06-09 routeAssist blocker evidence checklist 전파 보강: `map1_01a -> map2_02d` routeAssist waypoint guide/action/nudge marker 가 `out/web_playtest_route.*` blocker row 의 `missingEvidence` 5개와 `externalProofRequiredInputs` 3개를 구조화해서 싣게 했다. `HWANSE_LAST_ROUTE_ASSIST_WAYPOINT_RENDER`, `HWANSE_LAST_ROUTE_ASSIST_WAYPOINT_GUIDE`, `HWANSE_LAST_ACTION_PROMPT`, `HWANSE_LAST_ROUTE_ASSIST_WAYPOINT_NUDGE` 는 `routeBlockerMissingEvidenceCount=5`, `routeBlockerExternalProofInputCount=3`, `routeBlockerExternalProofHandoffStatus=blocked`, evidence matrix/handoff/audit link 를 노출한다. `tools/verify_route_guide_browser.py` 는 8013 기준 guide/nudge/follow 경로에서 missing evidence 목록(`strict source coordinate`, `tile hotspot confirmation`, `selected-root execution ref`, real selector `2:0` savedata, runtime trace/equivalent proof)과 외부 입력 id(`real-selector-2-0-save`, `normal-route-runtime-trace`, `strict-source-hotspot`)가 보존되는지 확인하고, `tools/summarize_completion_audit.py` 와 `tools/verify_web_assets.py` 는 completion audit evidence 에 `missingEvidence=5`, `externalProofInputs=3`, `handoff=blocked` 를 요구한다. 이는 후보 routeAssist 가 왜 trial-only 인지 브라우저 marker 에서 바로 추적하게 하는 증거/UX 보강이며, 원본 normal-route promotion proof 로 승격하지 않는다.
- 2026-06-09 strict hotspot 후보 checklist 표면 보강: `out/web_playtest_route.*` 는 `map1_01a -> map2_02d` strict hotspot 후보 4개를 `strictHotspotChecklist` 로 요약하고, `sourceTile`/`targetSpawn`, standable 여부, route assist/review 링크, failed gate, `selector-only-scene-list-no-strict-hotspot` 거절 분류를 함께 싣는다. `out/strict_source_hotspot_external_review_packet.html` 은 후보 표뿐 아니라 Evidence Refs/Related Reports 항목을 클릭 가능한 링크로 제공해 `map1_01a_strict_hotspot_review_matrix`, strict event tile signature scan, pattern contrast, source hotspot context 로 바로 이어진다. `web/index.html` 은 이 checklist 를 `routeBlockerStrictHotspotChecklist` 로 routeAssist waypoint/guide/prompt/nudge/action marker 에 전파하고, `tools/verify_route_guide_browser.py`, `tools/verify_web_assets.py`, `tools/summarize_completion_audit.py` 는 8013 기준 `candidates=4`, `rejected=4`, missing evidence 5개, failed gate 5개, reject classification 을 요구한다. 이는 strict source/hotspot 부재를 브라우저 런타임에서 직접 확인하기 위한 blocker visibility 보강이며, strict source coordinate, tile hotspot confirmation, real selector `2:0`, selected-root execution/runtime trace proof 가 없으므로 route promotion 은 계속 blocked 다.
- 2026-06-09 route next-action input class 정리: `out/route_investigation_queue.*`, `out/route_promotion_gate.*`, `out/completion_audit.*` 의 route next action 9개가 이제 `nextInputClasses`/`nextInputSummary` 를 보존한다. hard gate 는 `captured-gameplay-savedata`, `selected-root-execution-proof`, `runtime-trace-or-equivalent-proof`, `strict-source-coordinate-or-hotspot-proof`, `tile-hotspot-confirmation-proof` 로 매핑되며, markdown/html 표와 audit brief 에도 같은 입력 종류가 표시된다. 이는 open/blocked action 이 어떤 외부 증거를 기다리는지 명확히 하는 감사 보강이고, route promotion status 는 계속 blocked, completion audit 은 계속 `achieved=false` 다.
- 2026-06-09/11 WLK/MLK 오디오 제목 provenance 보강: `out/audio_title_provenance.*` 는 `PCMDATA.WLK` 가 효과음 이름 저장소를 갖지 않아 embedded title `0`, browser cue provenance `9`, EXE id entry `45` 로 표시된다는 점과, `MIDDATA.MLK` 는 MIDI track-name meta event 가 있는 16개만 제목을 갖고 4개(`02,06,11,17`)는 EXE id entry 라는 점을 고정한다. `legacy aggregate asset workbench (removed)` 의 WLK 항목은 `out/audio_archive_manifest.*` 의 EXE id 번호 체계를 그대로 보여주고 raw `extract_wlk/*.wav` 만 재생한다. `removed asset workbench browser smoke` 는 8013 기준 WLK raw manifest link 와 MLK `soundfont-player` preview 를 검증하고, `tools/verify_web_assets.py` 는 이 provenance 와 `out/goal_completion_checklist.*` 의 오디오 제목 요약을 함께 요구한다. 이는 resource viewer/audio UX 증거이며, route/event/battle completion proof 로 승격하지 않는다.
- 2026-06-09 legacy aggregate workbench enemy/object sprite 표면 보강: `legacy aggregate asset workbench (removed)` 은 `web/battle_analysis.html` 로 이어지는 적 스프라이트 검토 링크와 `asset filter: z, boss, enemy` 안내, `enemy+object` filter tooltip, `enemyObjectGalleryStatus=all-extracted-sprites-visible-in-enemy-object-filter` marker 를 노출한다. 8013 WebKit `removed asset workbench browser verifier` 는 전체 top-level PNG 132개, enemy 58개, object 7개, combined enemy/object sprite 65개, battle review 후보가 8 unique/21 row subset 이고 전체 extracted gallery 는 65개라는 summary 를 확인한다. 이는 사용자가 전투 후보 subset 을 전체 몬스터 수로 오해하지 않게 하는 legacy aggregate workbench UX/검증 보강이며, enemy row/stat/reward/formula binding 또는 original battle data proof 로 승격하지 않는다.
- 2026-06-10 관리 홈/진행상황 대시보드 보강: 기본 `/web/index.html` 은 게임 Canvas 가 아니라 `legacy aggregate asset workbench (removed)` 같은 일반 DOM 관리 홈으로 시작하며, 첫 화면은 카드형 게임 런처가 아니라 검색 가능한 테이블형 작업 메뉴와 우측 상태 지표로 구성한다. 게임은 테이블의 한 행으로만 남겨 `/web/game.html?game=1`, 후보 플레이는 `/web/game.html?play=1` 로 분리한다. 관리 홈은 `out/goal_completion_checklist.json` 도 직접 읽어 목표 완료 판정 `not achieved`, 체크리스트 `complete/total`, hard missing evidence 5개, next required input 3개, route promotion `blocked` 를 우측 패널에 바로 노출하고 `browserHomeGoalSummaryImplemented=True` marker 를 남긴다. `web/progress.html` 을 추가해 `out/goal_completion_checklist.json`, `out/completion_audit.json`, `out/playable_progress.json`, `out/event_battle_gap_audit.json` 을 직접 읽고 체크리스트 9개, 차단 gate 5개, 다음 입력 3개, 확정 진행 `2/174`, 원본 시스템 gap 을 일반 웹 뷰로 보여준다. `web/system_review.html` 은 `out/savedata_sample_coverage.json`, `out/savedata_sample_deltas.json`, `out/candidate_equipment_menu_browser_smoke.json`, `out/candidate_status_menu_browser_smoke.json` 을 묶어 후보 장비/상태 UX 는 smoke `passed` 이지만 원본 equipment/status/story save offset 은 아직 미매핑임을 한 화면에서 비교한다. `web/event_review.html` 은 `out/event_dialogue_blocks.json`, `out/battle_event_candidates.json`, `out/save_point_candidates.json`, `out/event_object_branch_state_candidate_links.json`, `out/event_vm_semantics_gap.json` 을 묶어 대사 블록 47개, 전투 후보 21개, 세이브포인트 후보 8개, 오브젝트 branch 후보 10개, event VM missing gate 7개를 검토한다. 이 화면은 browser partial replay 가 원본 event VM 으로 승격되지 않도록 `browserReplayPromotesOriginalEventVm=False`, `routeLinkedEventVmExecution=False`, `eventDrivenBattleEntry=False` 를 marker 로 노출한다. `web/map_review.html` 은 선택 맵의 `extract_fld/<map>.cns` 소스명, `out/maps_runtime_chunks/<map>.js` 런타임 청크, 소스 타일셋 PNG, 확정/후보 조립 render 를 상단 `source and assembled map` 요약으로 분리해 보여주며 `browserMapSourceSummaryImplemented=True` marker 를 노출한다. `web/monster_review.html` 은 몬스터/전투 후보의 소스 이미지, 공격명 후보, 공격별 프레임 후보 3개, 전체 프레임 스트립, battle candidate row 를 별도 검토 화면으로 노출하고 `browserMonsterAttackSequenceReviewImplemented=True`, `originalAttackSequenceBound=False` 를 marker 로 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 는 테이블 홈 `scene=home`, `tableRows>=16`, `goalChecks=4/9`, hard missing 5개, next input 3개, `progressChecks=9`, `blockers=5`, system samples 6/known `160/1274`, event dialogue 47/gates 7, `mapReview=map1_02b`, monster `attacks=3`/frames 24, `?game=1` title 진입을 WebKit 으로 확인하고, `tools/verify_web_assets.py` 는 `web/progress.html`/`web/system_review.html`/`web/event_review.html`/`web/map_review.html`/`web/monster_review.html` marker 와 고정 포트/기존 감사 산출물을 함께 검증한다. 이는 사용자가 진행상황과 partial/blocked 범위를 빠르게 확인하기 위한 관리자 UX 보강이며, completion audit 은 계속 `achieved=false`, 원본 normal-route/event/battle/equipment/status/story proof 로 승격하지 않는다.
- 2026-06-10 관리 홈 정적 분리 보강: 사용자가 지적한 “메인 랜딩이 게임처럼 보이는” 문제를 없애기 위해 기존 런타임을 `web/game.html` 로 분리하고, 기본 `web/index.html` 은 Canvas/게임 런타임 script/모바일 조작 UI 를 전혀 싣지 않는 일반 DOM 관리 홈으로 다시 작성했다. 기본 홈은 `legacy aggregate asset workbench (removed)` 과 같은 테이블/패널형 웹 뷰이며, `game.html?game=1`, `game.html?play=1`, `game.html?savedatScan=1` 을 명시 메뉴로 제공한다. 기존 산출물과 검토 화면의 쿼리형 실행 링크는 `game.html?...` 로 보정하고, `index.html` 은 query가 붙어도 게임으로 redirect하지 않는 작업 관리 인덱스로 유지한다. `web/game.html?game=1` 은 title runtime 으로 시작하고 title 메뉴의 `관리 홈` 은 정적 `index.html` 로 돌아간다. `legacy aggregate asset workbench (removed)`, `web/progress.html`, `web/system_review.html`, `web/event_review.html`, `web/monster_review.html`, `web/map_review.html`, `web/collision_review.html` 의 사용자-facing 게임 실행 링크도 `game.html?...` 로 갱신했다. 8013 기준 `tools/verify_home_landing_browser.py` 는 `canvasCount=0`, `runtimeScriptCount=0`, `browserStandaloneManagementHomeImplemented=True`, `browserGameRuntimeSplitImplemented=True`, `links game=game.html?game=1 play=game.html?play=1` 을 확인하고, `tools/verify_runtime_http.py` 와 `tools/verify_web_assets.py` 는 홈/런타임 분리를 각각 `index.html`/`game.html` 기준으로 검증한다. 이는 관리자 UX/작업 진행 가시성 보강이며, route promotion blocked 와 completion audit `achieved=false` 는 유지한다.

- 2026-06-10 progress 외부 입력 체크리스트 보강: `web/progress.html` 은 이제 `out/completion_audit.json` 의 `externalInputChecklist` 도 직접 읽어 `real-selector-2-0-save`, `normal-route-runtime-trace`, `strict-source-hotspot` 3개 외부 입력 항목을 별도 패널로 표시한다. 각 항목은 required input, unblocked gate, accepted signal, intake artifact, refresh command, not-accepted 조건을 함께 보여주며 `HWANSE_LAST_PROGRESS_RENDER.externalInputCount=3` marker 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 는 progress dashboard 에서 `externalInputs=3` 과 세 input id 가 모두 렌더되는지 확인하고, `tools/verify_web_assets.py` 는 `id="externalInputList"`, `renderExternalInputs()`, `externalInputChecklist` marker 를 정적으로 확인한다. 이는 사용자가 어떤 입력이 실제 route proof 로 인정되는지 관리 화면에서 바로 확인하게 하는 UX/증거 탐색 보강이며, captured selector `2:0` savedat, runtime trace/equivalent proof, strict source hotspot proof 자체를 대체하지 않는다.
- 2026-06-10 progress 로컬 진행 큐 보강: route proof blocker 에 매몰되지 않도록 `web/progress.html` 이 `out/completion_audit.json` 의 `openNextActions`/`blockedNextActions` 를 직접 읽어 `로컬 진행 큐` 패널에 표시한다. 현재 audit 기준 open action 7개와 blocked action 2개를 priority 순서로 보여주고, 각 항목은 task, why, failed gate, missing evidence, evidence refs, `nextInputSummary` 를 함께 노출한다. `HWANSE_LAST_PROGRESS_RENDER` 는 `openNextActionCount=7`, `blockedNextActionCount=2`, `browserLocalNextActionQueueImplemented=True` 를 남기며, 8013 기준 `tools/verify_home_landing_browser.py` 는 progress 화면에서 `로컬 진행 가능`, `외부 증거 필요`, `Prove predecessor fill-site execution/order` 문구와 open/blocked action 수를 검증한다. `tools/verify_web_assets.py` 는 `id="nextActionList"`, `renderNextActions()`, `openNextActions`, `blockedNextActions` marker 를 정적으로 확인한다. 이는 작업 흐름/우선순위 가시성 보강이고, selected-root execution, runtime trace/equivalent proof, real selector `2:0` captured savedata, strict source hotspot proof 를 대체하지 않으므로 completion audit 은 계속 `achieved=false` 다.
- 2026-06-10 progress 로컬 진행 큐 evidence ref 보강: `web/progress.html` 의 각 next action 카드가 이제 `evidenceRefs` 의 artifact 링크뿐 아니라 확인해야 할 JSON field 칩도 함께 보여준다. 화면은 action 카드 9개에서 표시 ref row 26개, field chip 130개를 노출하며, `HWANSE_LAST_PROGRESS_RENDER` 는 `nextActionEvidenceRefRowCount=26`, `nextActionEvidenceFieldChipCount=130`, `browserNextActionEvidenceRefsImplemented=True` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 가 이 DOM/marker 를 검증한다. 이는 다음 조사 항목이 어느 산출물의 어느 필드에 막혔는지 빠르게 추적하기 위한 관리자 UX 보강이며, external proof 자체나 route promotion 을 대체하지 않는다.
- 2026-06-10 event review VM 근거 패널 보강: `web/event_review.html` 은 이제 `out/event_vm_semantics_gap.json` 의 `eventVmOpcodeSemantics`, `eventTextSourceFlow`, `dialogueStorageIndex`, `eventVmPromotionGate` 를 직접 읽어 `VM opcode 근거` 와 `원본 VM 승격 gate` 패널을 별도로 표시한다. 화면은 text-source/render opcode length `0x0b:4`, `0x0c:20`, `0x0d:8`, cursor/separator `0x02:4`, control/display subset 11개와 1007개 grounded event, variable `0x08 mode0:4/mode1:8`, partial replay 47 blocks, `routeLinkedCommandsArePointerOverlap=True`, missing gate `7/7` 을 함께 보여준다. `HWANSE_LAST_EVENT_REVIEW_RENDER` 는 `browserEventVmOpcodeEvidencePanelImplemented=True`, `browserEventVmGatePanelImplemented=True`, `eventVmGroundedControlOpcodeCount=11`, `eventVmGroundedControlEventCount=1007`, `eventVmPartialReplayBlockCount=47`, `instructionLengthFullyDecoded=False`, `operandLayoutFullyDecoded=False` 를 남기며, 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 가 새 DOM/marker 를 검증한다. 이는 이벤트/대사/전투 리뷰에서 무엇이 grounded opcode evidence 이고 무엇이 원본 event VM runtime proof 가 아닌지 관리자가 바로 확인하게 하는 UX/증거 분리 보강이며, route-linked event VM execution, full browser event VM implementation, event-driven battle entry 로 승격하지 않는다.
- 2026-06-10 movement review 관리자 화면 보강: `web/movement_review.html` 을 추가해 `out/runtime_movement.json`, `out/input_keymap.json`, `out/mobile_browser_controls_smoke.json`, `out/candidate_movement_browser_smoke.json`, `out/original_collision_route_audit.json` 을 일반 DOM 화면으로 묶는다. 화면은 DirectInput primary action 16개/2 table, keyboard state `0x0055b868`, original frame 48ms, browser tile step 192ms, 16px tile projection, default collision `originalLayer1Flags`, party trail 7-slot cursor `0,4,1`, mobile joystick/menu smoke, field movement sound, collision bump, route collision proof false 를 보여준다. `HWANSE_LAST_MOVEMENT_REVIEW_RENDER` 는 `browserMovementReviewImplemented=True`, `inputActionCount=16`, `defaultTileStepMs=192`, `tileSizePixels=16`, `partyTrailRingSlotCount=7`, `originalCollisionRouteProofFound=False`, `originalActorSubTileInterpolationEvidenceFound=False`, `browserInterpolationOverlayNotPromotingOriginal=True`, `descriptorActivationCurrentSelectorActiveOrderStillUnproven=True` 를 남긴다. `web/index.html` 의 작업 메뉴와 nav 에 `이동/입력 검토` 를 추가했고, 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 가 새 페이지와 marker 를 검증한다. 이는 movement-input partial 의 근거와 남은 gap 을 관리 홈에서 바로 확인하기 위한 화면 보강이며, 원본 actor interpolation timing, current selector `2:0` active order, non-player descriptor behavior proof 로 승격하지 않는다.
- 2026-06-10 movement review 보행 trace 표면 보강: `web/movement_review.html` 은 `out/candidate_movement_browser_smoke.json` 의 deterministic movement snapshots 도 직접 보여준다. `보행 trace` 패널은 start/tick1/tick2/tick3/tick4/idle-after-complete 6개 샘플을 표시하고, 각 샘플의 selector, source rect, foot tile, frame, `interpolationOffset`, fixed-point projection 값을 노출한다. `HWANSE_LAST_MOVEMENT_REVIEW_RENDER` 는 `movementTraceSampleCount=6`, `movementTraceOriginalFrameMs=48`, `movementTraceDefaultTileStepMs=192`, `movementTraceWalkCadenceCommands=8`, `movementTraceSourceMatches=True`, `movementTraceProjectionMatches=True`, `movementTraceInterpolationOffsetCount=6`, `movementTraceFinalFootX=12`, `movementTraceFinalFootY=12`, `browserMovementTraceReviewImplemented=True` 를 남긴다. 이는 browser 48ms 보간/source-rect/projection 검증을 관리 화면에서 추적하기 위한 UX/증거 보강이며, 웹 `interpolationOffset` 은 계속 `browser-visual-overlay-not-original-proof` 로 분류되어 original actor interpolation proof 로 승격하지 않는다.
- 2026-06-10 collision/tile review 관리자 화면 보강: `web/collision_review.html` 을 추가해 `out/tile_classes.json`, `out/tile_class_coverage.json`, `out/map_tile_class_gaps.json`, `out/tile_pair_class_gaps.json`, `out/original_collision_route_audit.json`, `out/runtime_movement.json`, `out/candidate_movement_browser_smoke.json` 을 일반 DOM 화면으로 묶는다. 화면은 16개 타일셋의 pass/block class `439/1040`, pass/block pair `816/64`, 174개 맵 coverage 평균 `97.77%`/최저 `66.47%`, 완전 분류 59개 맵, map tile gap 1090행/115맵, pair gap 407행/13타일셋, fallback pass 12611개를 보여준다. 원본 충돌 쪽은 default collision `originalLayer1Flags`, tile step 192ms, party trail 7-slot, source standable 3개, target spawn standable 4개를 보여주지만 `originalCollisionRouteProofFound=False`, `promotionStatus=diagnostic-only`, missing gate 4개를 별도 카드로 노출한다. `HWANSE_LAST_COLLISION_REVIEW_RENDER` 는 `browserCollisionReviewImplemented=True`, `tileClassCoverageMapCount=174`, `tileClassCoverageAveragePct=97.77`, `mapTileClassGapRowCount=1090`, `tilePairClassGapRowCount=407`, `runtimeDefaultCollisionMode=originalLayer1Flags`, `browserCollisionReviewNonPromotingGapExposed=True` 를 남긴다. `web/index.html` 작업 메뉴/nav 에 `타일/충돌 검토` 를 추가했고, 8013 기준 `tools/verify_home_landing_browser.py` 는 이 화면이 일반 DOM 표로 coverage/gap 지표를 노출하는지 브라우저로 확인한다. 이는 통행/충돌 근거와 남은 gap 을 사용자가 빠르게 확인하기 위한 UX 보강이며, strict hotspot, selected-root execution, real selector `2:0` savedata, runtime trace proof 를 대체하지 않는다.
- 2026-06-10 collision review proof matrix 보강: `web/collision_review.html` 에 `충돌 proof matrix` 표를 추가해 CNS tile class source, original layer1 collision grid, browser collision runtime, map coverage, tile pair fallback gaps, source edge standability, target spawn standability, route promotion collision proof 를 8개 gate 로 분리했다. 표는 tile class source/original layer1 collision grid 2개를 grounded, browser collision runtime 1개를 passed, coverage/pair/source/target 4개를 partial, route promotion collision proof 1개를 blocked 로 요약해 `grounded 2 · passed 1 · partial 4 · blocked 1` 을 보여준다. `HWANSE_LAST_COLLISION_REVIEW_RENDER` 는 `browserCollisionProofMatrixImplemented=True`, `collisionProofMatrixRowCount=8`, `collisionProofMatrixGroundedRowCount=2`, `collisionProofMatrixPassedRowCount=1`, `collisionProofMatrixPartialRowCount=4`, `collisionProofMatrixBlockedRowCount=1`, `collisionProofMatrixRouteBlocked=True`, `collisionProofMatrixFirstBlockedId=route-promotion-collision` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 original layer1 flag 근거가 있어도 strict source hotspot/selected-root/real selector save/runtime trace 없이는 route promotion 으로 승격할 수 없다는 점을 관리자 화면에 고정하는 UX/증거 분리 보강이다.
- 2026-06-10 tile review 관리자 proof matrix 보강은 cleanup 과정에서 폐기했다. 구식 `web/tile_review.html` 은 최신 충돌/오버레이 해석과 맞지 않아 active surface 에서 삭제했고, 타일/충돌 근거는 `web/collision_review.html` 및 `web/map_review.html` 로 통합한다. local tile class 나 fallback queue 는 strict hotspot, selected-root execution, selector `2:0` savedata, runtime trace proof 로 승격하지 않는다.
- 2026-06-10 map review proof matrix 보강: `web/map_review.html` 의 source and assembled map 요약 아래에 `맵 proof matrix` 표를 추가해 source CNS, runtime map chunk, source tilesets, assembled render, render review state, candidate coverage, transition metadata, map-render-to-route proof 를 8개 gate 로 분리했다. 8013 기준 `map1_02b` 화면은 `extract_fld/map1_02b.cns`, `out/maps_runtime_chunks/map1_02b.js`, source tileset `map_b1,map_b2`, accepted render review, visible assembly candidate, transition row 를 함께 보여주고 현재 `grounded 3 · passed 2 · partial 2 · blocked 1` 로 요약한다. `HWANSE_LAST_MAP_REVIEW_RENDER` 는 `browserMapSourceSummaryImplemented=True`, `browserMapProofMatrixImplemented=True`, `mapProofMatrixRowCount=8`, `mapProofMatrixGroundedRowCount=3`, `mapProofMatrixPassedRowCount=2`, `mapProofMatrixPartialRowCount=2`, `mapProofMatrixBlockedRowCount=1`, `mapProofMatrixRouteProofBlocked=True`, `mapProofMatrixFirstBlockedId=map-render-to-route-proof`, `browserMapReviewNonPromotingRouteGapExposed=True` 를 남기며, `tools/verify_home_landing_browser.py` 는 실제 Chromium 에서 `map1_02b` source/assembled canvas 와 proof rows 를 확인하고 `tools/verify_web_assets.py` 는 DOM/marker 를 정적으로 검증한다. 이는 맵 소스와 조립 완성형을 보는 화면에서 visual/layout proof 와 normal-route proof 를 분리하는 관리자 UX/증거 보강이며, accepted map render 를 strict hotspot, event transition, selector execution, runtime trace proof 로 승격하지 않는다.
- 2026-06-10/11 format/VM review 관리자 화면 보강: `web/format_review.html` 을 추가해 `out/cns_payloads.json`, `out/event_vm_semantics_gap.json`, `out/directdraw_flow.json`, `out/exe_imports.json`, `out/audio_archive_manifest.json` 을 `legacy aggregate asset workbench (removed)` 과 같은 일반 DOM 검토 화면으로 묶는다. 화면은 `GENSE.FLD` 377 CNS, `PCMDATA.WLK` 54 효과음, `MIDDATA.MLK` 20 MIDI, CNS payload `image 177/tilemap 200`, field map 174, WLK/MLK manifest 검증 상태, DirectDraw `640x480x8`, Win32 import surface, save-selector handler 35 opcodes, event/object dispatch 64 entries, event VM missing gate 7개를 한 화면에 보여준다. `HWANSE_LAST_FORMAT_REVIEW_RENDER` 는 `browserFormatReviewImplemented=True`, `archiveFormatContainerCount=3`, `cnsPayloadCount=377`, `cnsImagePayloadCount=177`, `cnsTileMapPayloadCount=200`, `fieldMapCount=174`, `directDrawDisplayWidth=640`, `eventVmMissingGateCount=7`, `instructionLengthFullyDecoded=False`, `operandLayoutFullyDecoded=False`, `browserReplayPromotesOriginalEventVm=False`, `browserFormatReviewNonPromotingVmGapExposed=True` 를 남긴다. `web/index.html` 의 작업 메뉴와 nav 에 `포맷/VM 검토` 를 추가했고, 8013 기준 `tools/verify_home_landing_browser.py` 는 `formatCns=377`, `formatVmGates=7` 을 실제 브라우저로 확인하며 `tools/verify_web_assets.py` 는 새 DOM/marker 를 정적으로 검증한다. 이는 binary-formats partial 의 근거와 event VM 남은 gate 를 관리 홈에서 바로 확인하기 위한 UX/증거 분리 보강이며, full instruction decode, full operand layout, route-linked event VM execution, event-driven battle entry proof 로 승격하지 않는다.
- 2026-06-10 completion review 관리자 화면 보강: `web/completion_review.html` 을 추가해 `out/playable_progress.json`, `out/candidate_route_progress_browser_smoke.json`, `out/candidate_deep_route_browser_smoke.json`, `out/completion_audit.json`, `out/goal_completion_checklist.json` 을 일반 DOM 화면으로 묶는다. 화면은 확정 normal 진행 reachable `2/174`, confirmed transition 2/edge 1, map-exit trial reachable 13, save-selector candidate reachable 25, 짧은 후보 완료 `map2_14j`, 긴 routeAssist chain `map5_40f` 13 hop/14 visited maps, 후보 route-complete/route-clear title restore, prototype-playable-route-gate 상태, audit `achieved=false`, 원본 full-game completion false 를 분리해서 보여준다. `HWANSE_LAST_COMPLETION_REVIEW_RENDER` 는 `browserCompletionReviewImplemented=True`, `confirmedReachableMapCount=2`, `confirmedTransitionCount=2`, `confirmedEdgeCount=1`, `mapExitTrialReachableCount=13`, `saveSelectorCandidateReachableCount=25`, `shortRouteCompletionTarget=map2_14j`, `shortRouteCompletionGateOpen=True`, `shortRouteClearRestored=True`, `deepRouteTarget=map5_40f`, `deepRouteHopCount=13`, `deepRouteCompletionGateOpen=True`, `deepRouteClearCount=1`, `originalFullGameCompletionImplemented=False`, `originalRoutePromotionImplemented=False`, `completionAuditAchieved=False`, `completionGateChecklistStatus=partial`, `browserCompletionReviewNonPromotingGateExposed=True` 를 남긴다. `web/index.html` 의 작업 메뉴와 nav 에 `완료/클리어 검토` 를 추가했고, 8013 기준 `tools/verify_home_landing_browser.py` 는 `completionShort=map2_14j`, `completionDeep=13` 을 실제 브라우저로 확인하며 `tools/verify_web_assets.py` 는 새 DOM/marker 를 정적으로 검증한다. 이는 completion-gate partial 의 후보 완료/클리어 범위를 관리 홈에서 바로 확인하기 위한 UX/증거 분리 보강이며, 원본 full-game ending, normal-route promotion, story flag mutation proof 로 승격하지 않는다.
- 2026-06-10 route/progression review 관리자 화면 보강: `web/route_review.html` 을 추가해 `out/playable_progress.json`, `out/route_assist_frontier.json`, `out/route_promotion_gate.json`, `out/completion_audit.json` 을 일반 DOM 화면으로 묶는다. 화면은 확정 normal 진행 `2/174`, confirmed transition 2/edge 1, geometry-only map-exit trial reachable 13/transition 1401, save-selector candidate reachable 25/edge 272, 현재 frontier `map1_01a -> map2_02d`, selector `2:0`, geometry exit 후보 4개/auto 2개, promotion gate `blocked`, hard gate 5개, next review candidate 10개를 함께 보여준다. `HWANSE_LAST_ROUTE_REVIEW_RENDER` 는 `browserRouteReviewImplemented=True`, `startMap=map1_02b`, `confirmedReachableMapCount=2`, `confirmedTransitionCount=2`, `confirmedEdgeCount=1`, `mapExitTrialReachableCount=13`, `mapExitTrialTransitionCount=1401`, `saveSelectorCandidateReachableCount=25`, `saveSelectorCandidateEdgeCount=272`, `confirmedRouteBlockerCount=1`, `routeAssistFrontierCount=1`, `currentFrontierSource=map1_01a`, `currentFrontierTarget=map2_02d`, `routeAssistCandidateExitCount=4`, `routeAssistAutoCandidateExitCount=2`, `routePromotionStatus=blocked`, `routePromotionAllowed=False`, `routePromotionFailedGateCount=5`, `routePromotionHardGateCount=5`, `routePromotionNextActionCount=9`, `nextReviewCandidateCount=10`, `normalProgressionConfirmedComplete=False`, `browserRouteReviewNonPromotingTrialExposed=True` 를 남긴다. `web/index.html` 의 작업 메뉴와 nav 에 `루트/진행 검토` 를 추가했고, 8013 기준 `tools/verify_home_landing_browser.py` 는 `routeConfirmed=2/174`, `routeGate=blocked` 를 실제 브라우저로 확인하며 `tools/verify_web_assets.py` 는 새 DOM/marker 를 정적으로 검증한다. 이는 normal-progression partial 의 확정/후보/trial/gate 범위를 관리 홈에서 바로 확인하기 위한 UX/증거 분리 보강이며, routeAssist trial, geometry-only exits, selector-only frontier 를 normal-route promotion proof 로 승격하지 않는다.
- 2026-06-10 route review proof matrix 보강: `web/route_review.html` 에 `루트 proof matrix` 표를 추가해 confirmed route surface, confirmed transition edge, map-exit trial surface, save-selector routeAssist, current frontier candidate, next review queue, route promotion gate, external proof requirements 를 8개 gate 로 분리했다. 표는 confirmed transition edge 1개를 passed, confirmed surface/current frontier/next review queue 3개를 partial, geometry/selector trial 2개를 trial, promotion/external proof 2개를 blocked 로 요약해 `passed 1 · partial 3 · trial 2 · blocked 2` 를 보여준다. `HWANSE_LAST_ROUTE_REVIEW_RENDER` 는 `browserRouteProofMatrixImplemented=True`, `routeProofMatrixRowCount=8`, `routeProofMatrixPassedRowCount=1`, `routeProofMatrixPartialRowCount=3`, `routeProofMatrixTrialRowCount=2`, `routeProofMatrixBlockedRowCount=2`, `routeProofMatrixPromotionBlocked=True`, `routeProofMatrixFirstBlockedId=route-promotion-gate` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 routeAssist/geometry/selector 후보를 플레이 가능한 진행 보조로 유지하되 normal-route promotion, captured selector `2:0` savedata, selected-root runtime trace, strict hotspot proof 와 분리하는 관리자 UX/증거 보강이다.
- 2026-06-10 battle review 관리자 화면 보강: `web/battle_analysis.html` 을 추가해 `out/candidate_battle_browser_smoke.json`, `out/event_battle_gap_audit.json`, `out/original_battle_data_gap.json`, `out/battle_action_handler_context.json` 을 일반 DOM 화면으로 묶는다. 화면은 후보 전투 21개, 전투 배경 26개, 대사 블록 47개, 후보 메뉴 69개(row: event 4 + sprite 65), runtime selectable sprite 65개, battle-review unique sprite 8개, opcode `0x36` action handler `0x0041ff44`, action table `0x004d24ac`, 브라우저-local 전투 시작/히트 이펙트/필드 전투/승리/도주/패배/독 치료와 함께 원본 battle-entry dispatch, enemy row, formation, reward, combat formula proof false 를 보여준다. `HWANSE_LAST_BATTLE_REVIEW_RENDER` 는 `browserBattleReviewImplemented=True`, `candidateBattleStatus=passed`, `candidateBattleMenuCount=69`, `candidateBattleEventCount=4`, `candidateBattleSpriteCount=65`, `battleBackgroundCount=26`, `battleEventCandidateCount=21`, `eventDialogueBlockCount=47`, `battleEnemySpriteExtractedAssetCount=65`, `battleEnemySpriteRuntimeSelectableAssetCount=65`, `battleEnemySpriteCandidateUniqueSpriteCount=8`, `battleActionHandlerGrounded=True`, `battleActionOpcodeHex=0x36`, `battleActionHandlerVaHex=0x0041ff44`, `battleActionTableVaHex=0x004d24ac`, `battleActionTableEntryCount=7`, `battleActionOpcodeInDialogueStorage=False`, `battleEntryDispatchProofFound=False`, `originalBattleDataProofFound=False`, `enemyRowProofFound=False`, `formationTableProofFound=False`, `rewardTableProofFound=False`, `originalCombatFormulaIdentified=False`, `battleNumericPromotableEnemyRowCount=0`, `battleNumericPromotableRewardRowCount=0`, `actionBattleStartFeedbackVerified=True`, `pointerBattleHitEffectVerified=True`, `fieldEncounterVictoryVerified=True`, `completedBattleVictoryVerified=True`, `statusCureVerified=True`, `statusPersistVerified=True`, `browserBattleReviewNonPromotingGapExposed=True` 를 남긴다. `web/index.html` 의 작업 메뉴와 nav 에 `전투/후보 검토` 를 추가했고, 8013 기준 `tools/verify_home_landing_browser.py` 는 `battleCandidates=21`, `battleSprites=65` 를 실제 브라우저로 확인하며 `tools/verify_web_assets.py` 는 새 DOM/marker 를 정적으로 검증한다. 이는 event-dialogue-battle partial 의 후보 전투 구현 범위와 원본 전투 데이터 gap 을 관리 홈에서 바로 확인하기 위한 UX/증거 분리 보강이며, browser-local 후보 전투를 original event-driven battle entry, enemy stat row, formation/reward table, original combat formula proof 로 승격하지 않는다.
- 2026-06-10 dialogue/VM review 관리자 화면 보강: `web/dialogue_review.html` 을 추가해 `out/candidate_dialogue_progress_browser_smoke.json`, `out/event_dialogue_blocks.json`, `out/event_vm_semantics_gap.json`, `out/event_text_source_flow.json` 을 일반 DOM 화면으로 묶는다. 화면은 후보 대사 메뉴 3개, 선택 후보 `event-dialogue-block-026`, 대사 블록 47개/대사형 43개/맵 연결 7개/route-linked 0개, 텍스트 라인 810개/unique 605개, title restore 후 prototype dialogue completion 2개, branch replay 62 step/6 render/8 line advance/4 wait, render snapshot 2개, cursor-relative 37개/line layout 20개, literal payload 7개/branch literal match 10개, pointer/mobile/input wait latch smoke 통과를 보여준다. 동시에 original story flag runtime 과 original event VM runtime 은 false 로 유지하고, event VM promotion gate `7/7` missing, `browserReplayPromotesOriginalEventVm=False`, `routeLinkedEventVmExecution=False` 를 별도 gap 패널로 노출한다. `HWANSE_LAST_DIALOGUE_REVIEW_RENDER` 는 `browserDialogueReviewImplemented=True`, `candidateDialogueStatus=passed`, `dialogueBlockCount=47`, `dialogueCandidateMenuCount=3`, `branchExecSteps=62`, `renderStateSnapshotCount=2`, `literalEventCount=7`, `eventVmMissingGateCount=7`, `browserDialogueReviewNonPromotingGapExposed=True` 를 남긴다. `web/index.html` 의 작업 메뉴와 nav 에 `대사/VM 검토` 를 추가했고, 8013 기준 `tools/verify_home_landing_browser.py` 는 `dialogueBlocks=47`, `dialogueBranch=62` 를 실제 브라우저로 확인하며 `tools/verify_web_assets.py` 는 새 DOM/marker 를 정적으로 검증한다. 이는 event-dialogue-battle partial 중 대사/VM 표면을 따로 관리자가 확인하기 위한 UX/증거 분리 보강이며, browser-local candidate dialogue replay 를 route-linked event VM execution, full event VM implementation, original story flag mutation proof 로 승격하지 않는다.
- 2026-06-10 menu/shop review 관리자 화면 보강: `web/menu_review.html` 을 추가해 `out/candidate_shop_menu_browser_smoke.json`, `out/candidate_party_join_browser_smoke.json`, `out/candidate_skill_menu_browser_smoke.json`, `out/candidate_equipment_menu_browser_smoke.json`, `out/candidate_status_menu_browser_smoke.json` 을 일반 DOM 화면으로 묶는다. 화면은 상점 후보 메뉴 2개/아이템 6개/context 1개, prototype buy/sell/feedback/auto-save/title restore, 동료 메뉴 2개/합류 progress 2개/visible follower 2개/dialogue join 1개, 기술 메뉴 savedat learned `6/24` 와 member menu `2/10`, 장비 후보 18개/target menu 3개/Ataho target item 5개/equip-unequip stat delta/prototype battle attack+defense effect, 상태 메뉴 savedat member 3명/new-game member 1명을 한 화면에서 보여준다. 상세 표는 상점 6행, 동료 2행, 기술 6행, 장비 18행, 상태 4행을 각각 별도 표로 나누고, 동료는 manual join 2/dialogue join 1/follower 2/collision block 2, 상태는 savedata 3/prototype 1/Lv999 3/skill `6/24` 를 확인하게 한다. 동시에 original shop runtime, original price/inventory/money mutation, original party join event, original party trail runtime, original equipment offsets/effects, original combat formula, original story flag runtime 은 false 로 유지한다. `HWANSE_LAST_MENU_REVIEW_RENDER` 는 `browserMenuReviewImplemented=True`, `shopStatus=passed`, `shopItemCount=6`, `browserMenuPartyCandidateTableImplemented=True`, `partyCandidateTableRowCount=2`, `browserMenuStatusCandidateTableImplemented=True`, `statusCandidateTableRowCount=4`, `savedatSkillLearnedCount=6`, `equipmentCandidateCount=18`, `savedatStatusMemberCount=3`, `allCandidateMenuSmokePassed=True`, `browserMenuReviewNonPromotingOriginalSystemGapExposed=True` 를 남긴다. `web/index.html` 의 작업 메뉴와 nav 에 `메뉴/상점 검토` 를 추가했고, 8013 기준 `tools/verify_home_landing_browser.py` 는 `menuShop=passed`, `menuSkill=6/24`, `menuEquipment=18` 을 실제 브라우저로 확인하며 `tools/verify_web_assets.py` 는 새 DOM/marker 를 정적으로 검증한다. 이는 movement/input 이후 필드 메뉴와 상점/파티/기술/장비/상태 후보 기능을 관리자가 따로 확인하기 위한 UX/증거 분리 보강이며, browser-local menu smoke 를 original shop runtime, original party join/trail runtime, original equipment/status offsets, original combat formula, original story mutation proof 로 승격하지 않는다.
- 2026-06-10 save/object review 관리자 화면 보강: `web/object_position_review.html` 을 추가해 `out/candidate_save_point_browser_smoke.json`, `out/candidate_event_object_browser_smoke.json`, `out/save_point_candidates.json`, `out/event_object_branch_state_candidate_links.json` 을 일반 DOM 화면으로 묶는다. 화면은 save-point 후보 event block 8개, current-map menu 1개, 선택 `event-dialogue-block-033`, `map2_07e` 후보 세이브/회복/상태 cure 2개/title restore, inn context 3개, exact statue mention 0개, recovery NPC proof 0개를 보여준다. 이벤트 오브젝트 쪽은 `map2_03l` passive object 3개 loaded/rendered, object menu 4개 selected `zs_rg`, scene-linked z object `7/7`, descriptor field object 1개, object collision anchor 3개/overlay visible 1개/collision disabled pass, object-linked dialogue completion `3/3`, object inspect count 1, linked dialogue battle start/victory `3/3` 을 한 화면에 보여준다. 동시에 original save-point runtime, original event-object runtime, original linked-dialogue runtime, original story flag runtime 은 false 로 유지하고, current route object linked/range hit 는 0으로 표시한다. `HWANSE_LAST_OBJECT_REVIEW_RENDER` 는 `browserObjectSaveReviewImplemented=True`, `savePointStatus=passed`, `savePointCandidateEventBlockCount=8`, `savePointCandidateMenuCount=1`, `objectStatus=passed`, `sceneLinkedZObjectVerifiedCount=7`, `linkedDialogueCompleteCount=3`, `linkedDialogueBattleVictoryCount=3`, `browserObjectSaveReviewNonPromotingGapExposed=True` 를 남긴다. `web/index.html` 의 작업 메뉴와 nav 에 `세이브/오브젝트 검토` 를 추가했고, 홈은 게임식 랜딩이 아니라 `legacy aggregate asset workbench (removed)` 과 같은 일반 웹 관리 테이블/작업대 패널로 유지하도록 `browserAssetsStyleManagementHome=True` 검증 마커를 추가했다. 8013 기준 `tools/verify_home_landing_browser.py` 는 홈 DOM 테이블, `saveCandidates=8`, `objectLinks=7/7` 을 실제 브라우저로 확인하며 `tools/verify_web_assets.py`/`tools/verify_runtime_http.py` 는 새 DOM/marker/HTTP reachability 를 검증한다. 이는 event-dialogue-battle partial 중 세이브포인트와 오브젝트 후보 기능을 관리자가 따로 확인하기 위한 UX/증거 분리 보강이며, browser-local save/object smoke 를 original save point event, event object runtime, route-linked VM execution, original story mutation proof 로 승격하지 않는다.
- 2026-06-10 save/object review proof matrix 보강: `web/object_position_review.html` 에 `세이브/오브젝트 proof matrix` 표를 추가해 save-point candidate index, save-point browser smoke, object render/inspection, object collision overlay, linked dialogue/battle chain, original save-point runtime, original event-object runtime, route/story object binding 을 8개 gate 로 분리했다. 표는 세이브 후보 index 1개를 candidate, 후보 세이브 smoke/오브젝트 렌더/오브젝트 충돌/연결 대사·전투 4개를 passed, original save-point/event-object/route-story binding 3개를 missing 으로 요약해 `passed 4 · candidate 1 · missing 3` 을 보여준다. `HWANSE_LAST_OBJECT_REVIEW_RENDER` 는 `browserObjectProofMatrixImplemented=True`, `objectProofMatrixRowCount=8`, `objectProofMatrixPassedRowCount=4`, `objectProofMatrixCandidateRowCount=1`, `objectProofMatrixMissingRowCount=3`, `objectProofMatrixOriginalRuntimeMissing=True`, `objectProofMatrixFirstMissingId=original-save-point-runtime` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 세이브포인트/오브젝트 후보 smoke 와 원본 save/object/story runtime proof gap 을 한 화면에서 분리하는 관리자 UX/증거 보강이다.
- 2026-06-10 관리 홈/세이브 증거 화면 보정: `web/index.html` 은 더 이상 쿼리스트링을 `game.html` 로 자동 redirect 하지 않고, 어떤 URL 파라미터가 붙어도 `legacy aggregate asset workbench (removed)` 계열의 일반 DOM 관리 홈으로 유지된다. 게임 화면은 `타이틀 런타임 확인`/`후보 루트 런타임 확인` 같은 명시적 하단 보조 검증 도구 링크로만 들어간다. `web/savedata_review.html` 도 추가해 `out/savedata_slot_scan.json`, `out/save_selector_real_savedata_evidence_gap.json`, `out/savedata_sample_coverage.json`, `out/route_promotion_external_proof_handoff.json` 을 한 화면에 묶고, selector `2:0`/selected pointer `0x00540714` 에 필요한 captured savedata 조건, public sample 6개, 현재 selector 후보 0개, route evidence 후보 0개, 외부 입력 3개와 refresh/validation command 를 표시한다. `HWANSE_LAST_SAVEDATA_REVIEW_RENDER` 는 `browserSavedataReviewImplemented=True`, `savedataValidCount=6`, `savedataCurrentSelectorCandidateCount=0`, `savedataRealRouteEvidenceCandidateCount=0`, `realSavedataProofFound=False`, `externalInputChecklistCount=3` 을 남긴다. 8013 기준 `tools/verify_home_landing_browser.py`, `tools/verify_web_assets.py`, `tools/verify_runtime_http.py` 는 홈의 no-runtime/no-canvas/no-query-redirect 상태와 세이브 증거 DOM 페이지를 검증한다. 이는 route blocker 를 관리 홈에서 추적하기 위한 UX/증거 입력 보강이며, selector `2:0` captured savedata proof 또는 route promotion 으로 승격하지 않는다.
- 2026-06-10 외부 증거 검증 관리자 화면 보강: `web/proof_review.html` 을 추가해 `out/route_promotion_external_proof_handoff.json`, `out/route_promotion_external_proof_template.json`, `out/route_promotion_external_proof_validation.json`, `out/selected_root_execution_external_proof_packet.json`, `out/current_leaf_wrapper_external_proof_packet.json`, `out/strict_source_hotspot_external_review_packet.json` 을 일반 DOM 화면으로 묶는다. 화면은 route promotion `blocked`, proof package 9개(missing 7/blocked 2), 필요한 외부 입력 3개, accepted proof record 0개, hard blocker 5개를 지표로 보여주고, captured selector `2:0` savedata, selected-root runtime trace/equivalent proof, strict source/hotspot proof 각각의 required checks 와 validation/refresh command 를 표로 노출한다. `HWANSE_LAST_PROOF_REVIEW_RENDER` 는 `browserProofReviewImplemented=True`, `browserProofReviewDomTableView=True`, `proofPackageCount=9`, `requiredExternalInputCount=3`, `acceptedExternalProofRecordCount=0`, `selectedRootExternalProofFound=False`, `currentLeafWrapperExternalProofFound=False`, `strictSourceHotspotExternalReviewProofFound=False`, `strictHotspotCandidateCount=4`, `browserProofReviewNonPromotingGapExposed=True` 를 남긴다. `web/index.html` 작업 메뉴/nav 에 `외부 증거 검증` 을 추가했고, 8013 기준 `tools/verify_home_landing_browser.py`, `tools/verify_web_assets.py`, `tools/verify_runtime_http.py` 는 새 DOM 페이지와 홈 링크를 검증한다. 이는 사용자가 증거를 제출했을 때 어떤 gate 가 풀리는지 즉시 확인하기 위한 UX/검증 흐름 보강이며, 현재 상태에서는 route promotion 또는 원본 normal progression proof 로 승격하지 않는다.
- 2026-06-10 system/save review offset 표면 보강: `web/system_review.html` 은 이제 `out/savedata_sample_deltas.json` 의 route-critical offset 11개와 `out/savedata_sample_coverage.json` 의 known semantic field 94개/unknown varying range 87개를 일반 DOM 표로 노출한다. 화면은 selector group `0x0002` 가 현재 selector `2:0` 에 필요한 `0x02` 를 요구하지만 public sample selector `0:0`, `1:0`, `22:0` 에는 없다는 점, active descriptor order/gate/trap offset 의 public sample 값, 그리고 화면에서 즉시 확인 가능한 known field 16개와 unknown varying range 16개를 보여준다. `HWANSE_LAST_SYSTEM_REVIEW_RENDER` 는 `browserSavedataOffsetReviewImplemented=True`, `routeCriticalOffsetCount=11`, `routeCriticalExpectedMissingCount=1`, `knownSemanticFieldCount=94`, `unknownVaryingRangeCount=87`, `knownSemanticByteCount=160`, `unknownByteCount=1114` 를 남긴다. 이는 savedata mapping 과 route proof gap 을 더 잘 볼 수 있게 하는 관리자 UX/증거 표면 보강이며, captured selector `2:0` savedata 나 original story/system flag proof 로 승격하지 않는다.
- 2026-06-10 system/save review proof matrix 보강: `web/system_review.html` 에 `세이브/시스템 proof matrix` 표를 추가해 real save sample corpus, savedat semantic fields, route-critical offsets, candidate equipment menu, candidate status menu, equipment offset binding, status flag offsets, story flag runtime 을 8개 gate 로 분리했다. 표는 public save corpus/equipment/status smoke 3개를 passed, savedat semantic field 1개를 grounded, route-critical offset 1개를 partial, equipment/status/story 원본 offset/runtime 3개를 missing 으로 요약해 `passed 3 · grounded 1 · partial 1 · missing 3` 을 보여준다. `HWANSE_LAST_SYSTEM_REVIEW_RENDER` 는 `browserSystemProofMatrixImplemented=True`, `systemProofMatrixRowCount=8`, `systemProofMatrixPassedRowCount=3`, `systemProofMatrixGroundedRowCount=1`, `systemProofMatrixPartialRowCount=1`, `systemProofMatrixMissingRowCount=3`, `systemProofMatrixEquipmentOffsetsMissing=True`, `systemProofMatrixStoryFlagsMissing=True`, `systemProofMatrixFirstMissingId=equipment-offset-binding` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 savedata semantic coverage 와 후보 메뉴 smoke 가 원본 equipment/status/story flag proof 와 별개임을 고정하는 관리자 UX/증거 분리 보강이다.
- 2026-06-10 event review replay trace 표면 보강: `web/event_review.html` 은 이제 `out/event_vm_semantics_gap.json` 의 `browserDialogueReplaySmoke` 를 별도 `브라우저 replay trace` 패널로 노출한다. 화면은 branch execution `steps=62`, render `6`, line advance `8`, wait `4`, return `5`, render-state snapshot `2`, grounded control executed event `15`, literal CP949 payload replay, cursor/object focus, input wait latch 를 보여주고, 같은 패널에서 `browserFull=false`, `originalRuntime=false`, `storyFlags=false` 를 명시한다. `HWANSE_LAST_EVENT_REVIEW_RENDER` 는 `browserEventVmReplayTracePanelImplemented=True`, `eventVmBranchExecutionStepCount=62`, `eventVmBranchExecutionRenderCount=6`, `eventVmBranchExecutionLineAdvanceCount=8`, `eventVmBranchExecutionWaitCount=4`, `eventVmRenderStateSnapshotCount=2`, `eventVmGroundedControlExecutedEventCount=15`, `browserEventVmFullImplementation=False`, `originalEventVmRuntimeImplemented=False` 를 남긴다. 이는 후보 대사 replay 가 어느 정도 동작하는지 관리자 화면에서 빠르게 확인하기 위한 보강이며, route-linked event VM execution, original story flag mutation, full browser event VM, event-driven battle entry proof 로 승격하지 않는다.
- 2026-06-10/11 audio review 관리자 화면 보강: `web/audio_review.html` 을 추가해 `out/audio_archive_manifest.json`, `out/audio_title_provenance.json`, `removed asset workbench browser smoke`, `out/midi_bgm_test_browser_smoke.json`, `out/runtime_music_cue_browser_smoke.json`, `out/title_menu_sound_browser_smoke.json` 을 일반 DOM 검토 화면으로 묶는다. 화면은 WLK 54개 mono PCM, MLK 20개 SMF0 MIDI, EXE id 번호 체계, WLK title storage absent/embedded title 0/browser cue provenance 9/EXE id entry 45, MLK embedded title 16/20 및 EXE id entry 4개, raw WLK playback, MLK soundfont preview, title/map/battle runtime music cue smoke 를 한 화면에서 보여준다. `web/index.html` 작업 메뉴/nav 에 `음원 검토` 를 추가했고, 8013 기준 검증 도구는 `audioWlk=54`, `audioMlk=20`, manifest/soundfont 상태를 확인한다.
- 2026-06-10/11 audio review proof matrix 보강: `web/audio_review.html` 에 `음원 proof matrix` 표를 추가해 PCMDATA.WLK PCM 복원, MIDDATA.MLK MIDI 복원, EXE zero-based id 번호 체계, probe/audition 우회 제거, WLK/MLK 제목 provenance 를 분리했다. 표는 WLK/MLK 복원과 번호 체계를 complete 로, 제목 provenance 를 grounded 로 요약한다.
- 2026-06-10 monster review 기본 scope 보정: `web/monster_review.html` 은 내부 데이터상 `out/battle_enemy_candidates.json` 의 추출 enemy/object sprite 65개를 모두 갖고 있었지만, 기본 select 가 `전투 후보 몬스터`라 첫 화면에는 후보 8개만 보여 몬스터가 적게 보였다. 기본 scope 를 `추출 스프라이트 전체`로 바꾸고, 선택 asset 은 후보 row 가 있는 첫 스프라이트를 우선 잡아 공격/기술 후보와 전투 후보 표가 비지 않게 했다. `HWANSE_LAST_MONSTER_REVIEW_RENDER` 는 `scope=all`, `visibleRowCount=65`, `allExtractedEnemySpriteAssetCount=65`, `candidateEnemySpriteAssetCount=8`, `browserMonsterAllExtractedSpriteScopeDefault=True` 를 남기며, `tools/verify_home_landing_browser.py` 는 8013 브라우저에서 rowCount 65와 공격별 frame 후보 3개/12 frame 이상을 확인한다. 이는 추출 자산 가시성 보강이며, original enemy row/stat/formation/reward/formula 또는 original attack sequence proof 로 승격하지 않는다.
- 2026-06-10 monster review proof matrix 보강: `web/monster_review.html` 에 `몬스터 proof matrix` 표를 추가해 extracted enemy/object sprites, default visible monster scope, battle candidate proximity, attack/action text table, per-attack frame candidates, prototype profile stats/rewards, original enemy row/stat binding, original attack sequence/AI 를 8개 gate 로 분리했다. 표는 추출 스프라이트/공격 텍스트 2개를 grounded, 기본 65개 scope 1개를 passed, descriptor proximity/frame grouping 2개를 candidate, prototype stats 1개를 generated, original enemy row 와 original attack sequence 2개를 missing 으로 요약한다. `HWANSE_LAST_MONSTER_REVIEW_RENDER` 는 `browserMonsterProofMatrixImplemented=True`, `monsterProofMatrixRowCount=8`, `monsterProofMatrixGroundedRowCount=2`, `monsterProofMatrixPassedRowCount=1`, `monsterProofMatrixCandidateRowCount=2`, `monsterProofMatrixGeneratedRowCount=1`, `monsterProofMatrixMissingRowCount=2`, `monsterProofMatrixOriginalEnemyMissing=True`, `monsterProofMatrixFirstMissingId=original-enemy-row` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 몬스터 그래픽/공격 프레임 후보가 보이는 것과 원본 enemy row/stat/AI proof 가 아직 없는 것을 같은 화면에서 분리하는 관리자 UX/증거 보강이다.
- 2026-06-10 map gallery 관리자 화면 보강: 메인 랜딩을 게임식 화면이 아니라 `legacy aggregate asset workbench (removed)` 같은 일반 DOM 관리 화면으로 유지한 상태에서 `web/map_gallery.html` 을 추가했다. 화면은 `out/map_render_reviews.json` 의 261개 리뷰 행을 읽어 accepted 맵 174개를 기본 표로 보여주고, 각 맵마다 `extract_fld/<map>.cns` 소스 링크, accepted visual/tileset/tileIndex 조립 설정, `map_review.html` 조립 맵 링크, `game.html?map=...&overview=1` 별도 런타임 링크를 제공한다. rejected 87개 대체 리뷰 행과 family default 31개도 지표와 필터로 확인 가능하다. `HWANSE_LAST_MAP_GALLERY_RENDER` 는 `browserMapGalleryImplemented=True`, `browserMapGalleryDomTableView=True`, `mapRenderReviewRowCount=261`, `uniqueMapCount=174`, `acceptedMapCount=174`, `rejectedRowCount=87`, `sourceCnsLinkCount=174`, `mapReviewLinkCount=174`, `gameMapLinkCount=174`, `map1_02bAcceptedVisual=layer1UnderSceneTilesets` 를 남긴다. `web/index.html` 작업 메뉴/nav 에 `전체 맵 검토` 를 추가했고, 8013 기준 `tools/verify_home_landing_browser.py` 는 이 페이지가 canvas/runtime landing 이 아닌 일반 표로 174개 맵을 노출하는지 브라우저로 확인한다. 이는 맵 소스와 완성형 조립 상태를 빠르게 살피기 위한 관리자 UX 보강이며, map-exit/route promotion proof 로 승격하지 않는다.
- 2026-06-10 map gallery proof matrix 보강: `web/map_gallery.html` 에 `전체 맵 proof matrix` 표를 추가해 map-render review corpus, accepted map coverage, source CNS links, assembled map review links, game overview links, rejected alternate render rows, family default review rows, route-promotion separation 을 8개 gate 로 분리했다. 표는 review corpus 1개를 grounded, accepted coverage/source CNS/single-map review link 3개를 passed, rejected/family-default 2개를 partial, browser overview link 1개를 browser-only, route-promotion separation 1개를 blocked 로 요약해 `grounded 1 · passed 3 · partial 2 · browser-only 1 · blocked 1` 을 보여준다. `HWANSE_LAST_MAP_GALLERY_RENDER` 는 `browserMapGalleryProofMatrixImplemented=True`, `mapGalleryProofMatrixRowCount=8`, `mapGalleryProofMatrixGroundedRowCount=1`, `mapGalleryProofMatrixPassedRowCount=3`, `mapGalleryProofMatrixPartialRowCount=2`, `mapGalleryProofMatrixBrowserOnlyRowCount=1`, `mapGalleryProofMatrixBlockedRowCount=1`, `mapGalleryProofMatrixNonPromoting=True`, `mapGalleryProofMatrixFirstBlockedId=route-promotion-separation` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 174개 accepted 맵 조립 coverage 와 전체 맵 runtime overview 링크가 원본 route/event proof 와 별개임을 전체 맵 목록에서 고정하는 관리자 UX/증거 분리 보강이다.
- 2026-06-10 transition/exit review 관리자 화면 보강: `web/transition_review.html` 을 추가해 `out/map_exit_candidates.json`, `out/transition_reviews.json`, `out/route_assist_frontier.json`, `out/map1_01a_strict_hotspot_review_matrix.json` 을 일반 DOM 화면으로 묶었다. 화면은 geometry 출구 후보 맵 85개/출구 후보 449개/auto target hint 246개, 수동 전환 리뷰 24개(confirmed 2, rejected 22), 현재 frontier `map1_01a -> map2_02d`, candidate exit 4개/auto 2개, strict hotspot 후보 4개를 표와 카드로 보여준다. 기존 산출물의 `../web/game.html?...` 실행 링크는 관리 홈이 더 이상 게임으로 redirect 하지 않으므로 화면 안에서 `game.html?...` 로 변환해 별도 런타임 진입으로 제공한다. `HWANSE_LAST_TRANSITION_REVIEW_RENDER` 는 `browserTransitionReviewImplemented=True`, `browserTransitionReviewDomTableView=True`, `mapExitCandidateCount=449`, `transitionReviewRowCount=24`, `routeAssistFrontierCount=1`, `currentFrontierSource=map1_01a`, `currentFrontierTarget=map2_02d`, `strictHotspotProofFound=False`, `strictHotspotMissingEvidenceCount=3`, `strictHotspotTransitionReviewRowCount=0`, `strictHotspotEventTransitionCount=0` 을 남긴다. `web/index.html` 작업 메뉴/nav 에 `전환/출구 검토` 를 추가했고, 8013 기준 `tools/verify_home_landing_browser.py` 는 `transitionExits=449`, `transitionReviews=24` 를 실제 브라우저로 확인하며 `tools/verify_web_assets.py`/`tools/verify_runtime_http.py` 는 새 DOM/marker/reachability 를 검증한다. 이는 출구/입구 후보와 blocker 를 관리자가 한 화면에서 추적하기 위한 UX/증거 분리 보강이며, geometry 출구 후보나 selector-only frontier 를 normal-route promotion proof 로 승격하지 않는다.
- 2026-06-10 transition review proof matrix 보강: `web/transition_review.html` 에 `전환 proof matrix` 표를 추가해 confirmed transition review, manual transition review coverage, geometry exit candidates, root-aware shortlist, routeAssist frontier, strict source hotspot, real selector `2:0` savedata, selected-root runtime trace 를 8개 gate 로 분리했다. 표는 confirmed transition 1개를 passed, manual review coverage 1개를 partial, geometry/root shortlist 2개를 candidate, routeAssist/strict hotspot/savedata/runtime trace 4개를 blocked 로 요약해 `passed 1 · partial 1 · candidate 2 · blocked 4` 를 보여준다. `out/transition_review_shortlist_audit.json` 도 읽어 shortlist row 24개, strict event-linked row 24개, patch preview match 24개, `promotionStatus=not-auto-confirmed`, `reviewMode=manual-review-only` 를 화면 marker 에 포함한다. `HWANSE_LAST_TRANSITION_REVIEW_RENDER` 는 `browserTransitionProofMatrixImplemented=True`, `transitionProofMatrixRowCount=8`, `transitionProofMatrixPassedRowCount=1`, `transitionProofMatrixPartialRowCount=1`, `transitionProofMatrixCandidateRowCount=2`, `transitionProofMatrixBlockedRowCount=4`, `transitionProofMatrixRoutePromotionBlocked=True`, `transitionProofMatrixFirstBlockedId=routeassist-frontier` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 맵 출구/입구 후보와 실제 route promotion blocker 를 한 화면에서 분리하는 관리자 UX/증거 보강이며, 수동 shortlist/geometry 후보를 normal-route proof 로 승격하지 않는다.
- 2026-06-10 selector/root evidence review 관리자 화면 보강: `web/selector_review.html` 을 추가해 `out/route_investigation_queue.json`, `out/route_promotion_gate.json`, `out/save_selector_selected_root_execution_gap.json`, `out/save_selector_merge_runtime_context.json`, `out/save_selector_predecessor_fill_execution_order_gap.json`, `out/save_selector_wrapper_execution_gap.json`, `out/save_selector_route_pair_entry_execution_gap.json`, `out/save_selector_opcode20_context_f2_sources.json`, `out/save_selector_opcode24_mode1_runtime_context.json` 을 일반 DOM 화면으로 묶었다. 화면은 promotion gate 5개 모두 실패, 조사 action 9개(open 7/blocked 2), selected-root proof false/failed gate 8/missing 5, predecessor fill proof gate 10/10 blocked, selector merge shape-only/forward bridge absent, wrapper corrected-trace gap, route-pair entry failure, opcode20 refs 204/object selectors 16, opcode24 runtime producer failed gate 3/covering writes 0 을 한 화면에 표시한다. `HWANSE_LAST_SELECTOR_REVIEW_RENDER` 는 `browserSelectorReviewImplemented=True`, `browserSelectorReviewDomTableView=True`, `gateChecklistCount=5`, `failedGateCount=5`, `selectedRootProofFound=False`, `selectedRootConstructedDiagnosticReachedRouteSelector=True`, `predecessorFillProofGateBlockedCount=10`, `selectorMergeShapeOnly=True`, `wrapperCorrectedTraceNormalSelectionGapFound=True`, `opcode20ReferenceCount=204`, `opcode24FailedGateCount=3` 을 남긴다. `web/index.html` 작업 메뉴/nav 에 `셀렉터/루트 증거 검토` 를 추가했고, 8013 기준 `tools/verify_home_landing_browser.py` 는 `selectorGate=5`, `selectorActions=9` 를 실제 브라우저로 확인하며 `tools/verify_web_assets.py`/`tools/verify_runtime_http.py` 는 새 DOM/marker/reachability 를 검증한다. 이는 selected-root/merge/predecessor/opcode 증거를 관리자가 한 화면에서 추적하기 위한 UX/증거 분리 보강이며, constructed diagnostic selector `2:0` 또는 shape-only merge 를 normal-route selected-root proof 로 승격하지 않는다.
- 2026-06-10 battle review 원본 숫자 후보 표면 보강: `web/battle_analysis.html` 은 이제 `out/original_battle_numeric_context.json` 도 직접 읽어 원본 전투 데이터 gap 옆에 descriptor-local numeric run 후보를 표시한다. 화면은 battle-related descriptor context 123개, 후보 background/enemy pair 21개, close pair 9개, plain numeric run 32개, local run pair 16개, close local run pair 8개와 대표 후보 6개 이상의 값 배열/거리/차단 사유를 보여준다. `HWANSE_LAST_BATTLE_REVIEW_RENDER` 는 `battleNumericDescriptorContextCount=123`, `battleNumericCandidatePairContextCount=21`, `battleNumericCloseCandidatePairContextCount=9`, `battleNumericPlainRunCount=32`, `battleNumericCandidateContextsWithLocalRuns=16`, `battleNumericCloseCandidateContextsWithLocalRuns=8`, `battleNumericDescriptorOnlyBlocked=True`, `browserBattleNumericContextReviewImplemented=True` 를 남긴다. 이 숫자 후보는 `descriptor-context-only-no-handler-row-stride-or-runtime-edge` 로 계속 차단되며, enemy row/stat/formation/reward/combat formula 또는 original battle-entry proof 로 승격하지 않는다.
- 2026-06-10 battle review 원본 숫자 후보 triage 보강: `web/battle_analysis.html` 의 `원본 숫자 후보` 요약 옆에 `숫자 후보 triage` 표를 추가해, 후보 21개 중 local numeric run 이 있는 background/enemy pair 를 우선 정렬하고 16개 행의 candidate id, `btl_* + z*/boss_*` pair, background/enemy descriptor ref VA, ref distance, numeric run 값/VA range/relative dword, 차단 사유를 한 화면에서 스캔할 수 있게 했다. `HWANSE_LAST_BATTLE_REVIEW_RENDER` 는 `browserBattleNumericTriageTableImplemented=True`, `battleNumericTriageRowCount=16`, `battleNumericTriageLocalRunRowCount=16`, `battleNumericTriagePromotableRowCount=0`, `battleNumericTriageNonPromotingBlocked=True`, 첫 run 값 `304, 0, 384, 80, 16, 16, 63` 을 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 이 표와 marker 를 검증한다. 이는 원본 전투 데이터 후보를 작업 가능한 표면으로 정리한 관리자 UX 보강이며, handler row stride/runtime binding 없이 enemy row/stat/reward/formula proof 로 승격하지 않는다.
- 2026-06-10 battle review proof matrix 보강: `web/battle_analysis.html` 에 `전투 proof matrix` 표를 추가해 candidate battle smoke, battle resource sprites, battle action handler, browser battle loop, browser party/enemy attack frame animation, numeric row candidates, original battle entry, original enemy/formation, original reward/formula 를 10개 gate 로 분리했다. 표는 리소스/액션 핸들러 2개를 grounded, 후보 전투 smoke/브라우저 전투 루프/party frame animation/enemy frame animation 4개를 passed, 숫자 후보 triage 1개를 candidate, original battle entry/enemy formation/reward formula 3개를 missing 으로 요약해 `grounded 2 · passed 4 · candidate 1 · missing 3` 을 보여준다. `HWANSE_LAST_BATTLE_REVIEW_RENDER` 는 `browserBattleProofMatrixImplemented=True`, `battleProofMatrixRowCount=10`, `battleProofMatrixGroundedRowCount=2`, `battleProofMatrixPassedRowCount=4`, `battleProofMatrixCandidateRowCount=1`, `battleProofMatrixMissingRowCount=3`, `battleProofMatrixOriginalBattleMissing=True`, `battleProofMatrixFirstMissingId=original-battle-entry` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 브라우저-local 전투 루프와 추출 리소스/숫자 후보가 원본 battle entry/enemy/reward/formula proof 와 별개임을 고정하는 관리자 UX/증거 분리 보강이다.
- 2026-06-10 battle review 원본 전투 데이터 gate 상세 표 보강: `web/battle_analysis.html` 에 `원본 전투 데이터 gate 상세` 표를 추가해 `out/original_battle_data_gap.json` 의 실패 gate 7개(`event-battle-dispatch`, `enemy-row-sprite-binding`, `enemy-stat-table`, `formation-table`, `encounter-table`, `reward-table`, `combat-formula`)를 그대로 보여준다. 각 행은 현재 확인된 근거(opcode `0x36` action handler, 65개 runtime selectable sprite, 123개 descriptor context/32개 numeric run/16개 local run pair, browser field encounter smoke, prototype reward/status/damage loop), 필요한 원본 proof, `candidate-browser-or-descriptor-evidence-only` 차단 사유를 함께 표시하고 모든 행을 `missing` 으로 유지한다. `HWANSE_LAST_BATTLE_REVIEW_RENDER` 는 `browserOriginalBattleGateDetailTableImplemented=True`, `originalBattleGateRowCount=7`, `originalBattleGateMissingRowCount=7`, `originalBattleGateRemainingProofCount=7`, `originalBattleGateEvidenceSourceCount=9`, `originalBattleGateDispatchMissing=True`, `originalBattleGateRewardFormulaStillMissing=True` 를 남기며, 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 가 DOM/marker 를 검증한다. 이는 후보 전투가 동작하는 것과 원본 enemy row/stat/formation/encounter/reward/combat formula proof 미확보 상태를 더 세밀하게 분리하는 관리자 UX 보강이며, original battle data proof 로 승격하지 않는다.
- 2026-06-10 progress dashboard 작업 의존성 분리 보강: `web/progress.html` 의 `openNextActions` 가 실제로는 selected-root trace, captured selector `2:0` savedata, strict hotspot proof 같은 외부 증거를 요구하는데도 모두 `로컬 진행 가능` 으로 보이던 문제를 고쳤다. 새 `작업 분리` 패널은 현재 루트 승격 큐를 `로컬 실행 가능 0 / 외부 증거 대기 9` 로 분리하고, 외부 증거 없이 승격 가능한 항목이 없다는 문구와 상위 외부 증거 대기 항목 5개를 일반 DOM 카드로 보여준다. `HWANSE_LAST_PROGRESS_RENDER` 는 `browserProgressActionDependencySplitImplemented=True`, `localExecutableActionCount=0`, `externallyConstrainedActionCount=9`, `splitActionCardCount=5`, `hardMissingEvidenceCount=5`, `routePromotionStatus=blocked` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 는 이 마커와 `외부 증거 대기` 라벨을 브라우저에서 확인하고, `tools/verify_web_assets.py` 는 정적 DOM/marker 를 강제한다. 이는 작업 우선순위가 route blocker 에 매몰되지 않도록 하는 관리자 진행 표시 보강이며, route promotion 또는 original normal progression proof 로 승격하지 않는다.
- 2026-06-10 progress dashboard 전체 목표 산출물 매트릭스 보강: `web/progress.html` 에 `전체 목표 산출물 매트릭스` 표를 추가해 `out/completion_audit.json` 의 `promptToArtifactChecklist` 11개 항목을 요구사항/상태/산출물/gap 으로 직접 보여준다. 표는 `docs/GOAL.md` 유지, 작업 순서 1-8, primary route deliverable, validation gates 를 한 화면에 묶고 현재 `complete 4 · partial 7 · missing 0` 으로 요약한다. `HWANSE_LAST_PROGRESS_RENDER` 는 `browserGoalArtifactMatrixImplemented=True`, `goalArtifactMatrixRowCount=11`, `goalArtifactMatrixCompleteCount=4`, `goalArtifactMatrixPartialCount=7`, `goalArtifactMatrixRouteDeliverablePartial=True`, `goalArtifactMatrixValidationPartial=True`, `goalArtifactMatrixNonAchieved=True` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 사용자가 전체 목표 대비 현재 작업 위치를 route blocker 와 분리해 확인하기 위한 관리자 UX 보강이며, completion audit `achieved=false` 와 route promotion `blocked` 는 유지한다.
- 2026-06-10 movement review proof matrix 보강: `web/movement_review.html` 의 이동/입력 검토에 `이동 proof matrix` 표를 추가해 입력 mask, 16px 타일 투영, actor tile mutation, collision flag grid, party trail ring, sprite frame selector, 보간/타이밍, active descriptor order 를 행 단위로 분리했다. 표는 원본 근거, 브라우저 구현, 남은 gap 을 함께 보여주며 `grounded 6 / browser-only 1 / partial 1` 로 요약한다. `HWANSE_LAST_MOVEMENT_REVIEW_RENDER` 는 `browserMovementProofMatrixImplemented=True`, `movementProofMatrixRowCount=8`, `movementProofGroundedRowCount=6`, `movementProofBrowserOnlyRowCount=1`, `movementProofPartialRowCount=1`, `movementProofOriginalInterpolationStillUnproven=True`, `movementProofCurrentSelectorActiveOrderStillUnproven=True` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 proof matrix DOM/marker 를 검증한다. 이는 movement/input 구현 근거와 남은 original timing/current-selector gap 을 관리자가 빠르게 볼 수 있게 하는 UX/증거 분리 보강이며, original actor interpolation timing 또는 selector `2:0` active order proof 로 승격하지 않는다.
- 2026-06-05 후보 오브젝트 연결 전투 체인 보강: `map2_03l` 오브젝트 조사와 세 연결 대사를 완료한 뒤 title/quick-load 로 복원해도 `Enter -> 대사 전투 btl_l1` 프롬프트가 유지되고, `event-dialogue-block-041:btl_l1` 전투가 실제 battle scene 으로 시작한다. 첫 승리 후 objective/prompt 는 `후보 대사 전투 btl_l2` / `Enter -> 대사 전투 btl_l2` 로 전진하고, 이어 `event-dialogue-block-032:btl_l2`, `event-dialogue-block-004:btl_l1` 까지 순서대로 승리해 `battleStartCount=3`, `battleVictoryCount=3`, `pendingLink=None`, `dropCount=3`, 최종 objective/prompt `후보 전투 완료 btl_l1` / `Enter -> 전투 완료 btl_l1` 을 남긴다. 마지막 Enter/A 는 `battle-complete:event-dialogue-block-004` 완료 알림을 열고 `전투 보상 소지금 114 / 경험치 +9`, `전투 드롭 해독초 3` 를 표시하며, `duplicateProgress=True` 로 진행 기록을 중복하지 않는다. 완료된 전투 프롬프트가 같은 좌표의 상점 후보에 덮이지 않도록 `drawActionPrompt()` 와 `activateSecondaryCandidateAtFoot()` 의 우선순위도 맞췄다. `tools/verify_candidate_event_object_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 smoke/감사 산출물에 이 체인을 필수 증거로 요구한다. 이는 browser-local prototype 전투 루프 보강이며, 원본 event-driven battle entry/story flag proof 로 승격하지 않는다.
- 2026-06-07 후보 오브젝트 연결 전투 WLK sound 검증 보강: `map2_03l` 오브젝트 조사 뒤 이어지는 `event-dialogue-block-041:btl_l1` 전투 시작 smoke 도 이제 일반 후보 전투처럼 `battleStartFeedbackSound=battleStart:../extract_wlk/08.wav:True`, `battleStartSound=battleStart`, `battleStartSoundSrc=../extract_wlk/08.wav` 를 요구한다. 첫 승리와 남은 2연전 보상 overlay 는 `rewardEffectSound=victory:../extract_wlk/12.wav:True`, `rewardEffectSounds=victory,victory`, `rewardEffectSoundSrcs=../extract_wlk/12.wav,../extract_wlk/12.wav` 로 고정해 3연전이 화면 reward feedback 뿐 아니라 WLK 승리음 피드백도 남기는지 확인한다. `tools/verify_candidate_event_object_browser.py`, `tools/verify_web_assets.py`, `tools/summarize_completion_audit.py` 를 8013 기준으로 맞췄고, 이는 연결 전투 gameplay 피드백 검증 보강이지 원본 event-driven battle entry, reward table, story flag proof 로 승격하지 않는다.
- 2026-06-07 전투 완료 알림 overlay/WLK sound 보강: 완료된 후보 전투의 `Enter -> 전투 완료 ...`, 현재 `목표`, 런타임 메뉴 `전투 완료 ...` 경로가 완료 대화만 여는 데서 끝나지 않게 `battle-completion-feedback` overlay 를 맵 화면 위에 표시하고 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 남기게 했다. `web/index.html` 은 `HWANSE_BATTLE_COMPLETION_FEEDBACK_LOG`, `HWANSE_LAST_BATTLE_COMPLETION_FEEDBACK`, `HWANSE_BATTLE_COMPLETION_FEEDBACK_RENDER`, `HWANSE_LAST_BATTLE_COMPLETION_FEEDBACK_RENDER` 를 노출한다. `tools/verify_candidate_battle_browser.py` 는 8013 기준 일반 `btl_b1` 완료 복원과 title continue 복원에서 `completionFeedback=battle-completion-feedback:전투 완료 btl_b1`, `completionFeedbackRender=True`, `completionFeedbackSound=menuConfirm:../extract_wlk/04.wav:True` 를 요구하고, `tools/verify_candidate_event_object_browser.py` 는 `map2_03l` 연결 3연전 마지막 완료 알림도 `전투 완료 btl_l1` feedback 으로 확인한다. 이는 완료된 전투 확인 조작을 실제 플레이 화면/효과음으로 보이게 하는 UX 보강이며, 원본 event-driven battle entry, reward table, story flag proof 로 승격하지 않는다.
- 2026-06-07 맵 전환 완료 알림 overlay/WLK sound 보강: confirmed 전환 진행을 완료한 뒤 현재 `목표`/title `이어하기` 복원 목표에서 `transition-complete:map1_01a` 완료 알림을 열 때도 `map-transition-completion-feedback` overlay 를 맵 화면 위에 표시하고 `menuConfirm` WLK 사운드(`../extract_wlk/04.wav`)를 남긴다. `web/index.html` 은 `HWANSE_MAP_TRANSITION_COMPLETION_FEEDBACK_LOG`, `HWANSE_LAST_MAP_TRANSITION_COMPLETION_FEEDBACK`, `HWANSE_MAP_TRANSITION_COMPLETION_FEEDBACK_RENDER`, `HWANSE_LAST_MAP_TRANSITION_COMPLETION_FEEDBACK_RENDER` 를 노출한다. `tools/verify_candidate_transition_progress_browser.py` 는 8013 기준 direct confirmed 전환 직후와 title continue 복원 뒤 양쪽에서 `transitionCompletionFeedback=map-transition-completion-feedback:맵 전환 완료 map1_01a`, `transitionCompletionFeedbackRender=True`, `transitionCompletionSound=menuConfirm:../extract_wlk/04.wav:True` 를 요구하고, `tools/verify_web_assets.py`/`tools/summarize_completion_audit.py` 도 같은 marker 를 completion audit evidence 로 보존한다. 이는 완료된 맵 전환 확인 조작을 실제 플레이 화면/효과음으로 보이게 하는 UX 보강이며, 원본 story flag runtime, route promotion, DirectSound timing proof 로 승격하지 않는다.
- 2026-06-09 이벤트 VM promotion gate 보강: `out/event_vm_semantics_gap.*` 에 `browserReplayClassification=browser-partial-known-opcode-replay-not-original-event-vm-runtime`, `browserReplayPromotesOriginalEventVm=False`, `eventVmPromotionGatePassed=False` 를 추가하고, 누락 gate 를 `fullInstructionLengthDecode`, `fullOperandLayoutDecode`, `routeLinkedEventVmExecution`, `sceneEventDialogueBinding`, `originalStoryFlagMutation`, `fullBrowserEventVmImplementation`, `eventDrivenBattleEntry` 로 구조화했다. `tools/summarize_event_battle_gap_audit.py` 와 `tools/summarize_completion_audit.py` 는 이 gate 를 상위 감사 evidence/gap 으로 전파하고, `tools/verify_web_assets.py` 는 event VM gap, event/battle gap audit, completion audit 에 같은 non-promoting 분류가 없으면 실패하도록 고정한다. 이는 브라우저 partial replay/control-display 적용이 원본 event VM runtime proof 로 오인되지 않게 하는 증거 분리 보강이며, completion audit 은 계속 `achieved=false` 다.
- 2026-06-10 작업 관리 인덱스 표현 보정: `web/index.html` 의 보이는 제목을 `환세취호전 작업 관리` 로 낮추고, `data-view-mode="management-index"`, `mode="management-index"`, `uiKind="assets-style-dom-table"`, `browserHomeNotGameLanding=True`, `browserHomeCanvasRuntime=False` marker 를 추가했다. 첫 화면은 `legacy aggregate asset workbench (removed)` 처럼 검색 가능한 표, 진행 지표, 목표 상태 패널로 유지하며 Canvas/runtime script 는 싣지 않는다. 게임 진입은 `game.html?game=1`, 후보 플레이와 savedata scan 은 `game.html?...` 명시 링크로만 제공하고, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 no-canvas 관리 인덱스와 별도 게임 런타임 분리를 검증한다. 이는 메인 화면이 게임형 랜딩처럼 보이지 않도록 하는 관리자 UX 보강이며, route promotion 이나 completion audit 완료로 승격하지 않는다.
- 2026-06-10 작업 관리 인덱스 우선순위 보정: 사용자가 다시 지적한 "메인 랜딩을 게임처럼 만들면 안 된다"는 요구에 맞춰 `web/index.html` 의 표 제목을 `작업 검토 메뉴` 로 바꾸고, 첫 표 항목이 `game.html?game=1` 이 되지 않도록 실행 항목을 검토/증거/맵/몬스터/진행 항목 뒤로 낮췄다. `HWANSE_LAST_HOME_RENDER` 는 `firstMenuHref`, `browserHomeGameEntryDemoted=True` 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 기본 홈의 첫 표 항목이 게임 실행이 아닌 일반 관리 테이블임을 검증한다. 이는 관리자 웹뷰 표현 보강이며, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-10 `game.html` 무쿼리 진입 보정: 사용자가 `web/game.html` 을 직접 열었을 때도 게임 타이틀로 시작하지 않도록 bare entry 를 `index.html` 관리 홈으로 redirect 하고, 런타임 title 진입은 `game.html?game=1`, `?title=1`, `?play=1` 처럼 명시 쿼리가 있을 때만 허용하도록 `START_GAME_MENU` 조건을 좁혔다. 또한 `game.html` 의 초기 body class 를 `runtime-mode` 로 고정해 예전 game-home DOM 이 redirect 전 플래시되지 않게 했다. `tools/verify_home_landing_browser.py` 는 8013 WebKit smoke 에서 `/web/game.html` 이 `/web/index.html` 로 이동하고 `canvasCount=0`, `runtimeScriptCount=0`, `browserHomeNotGameLanding=True` 를 유지하는지 검증하며, `tools/verify_runtime_http.py` 와 `tools/verify_web_assets.py` 는 정적 marker 를 요구한다. 이는 메인 랜딩이 게임 화면처럼 보이지 않게 하는 관리자 UX 보강이며, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-10 savedata review proof matrix 보강: `web/savedata_review.html` 에 `세이브 proof matrix` 표를 추가해 real captured save corpus, selector `2:0` byte pair, selected pointer `0x00540714`, `map1_01a -> map2_02d` route pair, public sample coverage, route-critical offsets, synthetic diagnostic exclusion, external proof inputs 를 8개 gate 로 분리했다. 현재 표는 `passed 1 / blocked 4 / partial 2 / excluded 1` 로 요약되며, public save 6개는 유효하지만 required byte pair count 0, selected pointer real save count 0, route pair count 0, route-critical offsets 11개 중 expected missing 1개, block reason 5개를 보여준다. `HWANSE_LAST_SAVEDATA_REVIEW_RENDER` 는 `browserSavedataProofMatrixImplemented=True`, `savedataProofMatrixRowCount=8`, `savedataProofMatrixBlockedRowCount=4`, `routeCriticalOffsetCount=11`, `routeCriticalExpectedMissingCount=1`, `validRealCandidateBlockReasonCount=5`, `savedataProofMatrixNonPromotingBlocked=True` 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 이 DOM/marker 를 검증한다. 이는 captured selector `2:0` savedata 부재를 관리자 화면에서 더 명확히 보여주는 UX/증거 분리 보강이며, route promotion 또는 selected-root proof 로 승격하지 않는다.
- 2026-06-10 event review original proof matrix 보강: `web/event_review.html` 에 `원본 event/battle proof matrix` 표를 추가해 route-linked event VM execution, event-driven battle entry, original enemy data, original combat formulas, original rewards, equipment ownership/equipped offsets, original status flag offsets, story flag mutation 을 8개 원본 gate 로 분리했다. 표는 브라우저/추출 증거(대사 47개, branch replay 62 step, 전투 후보 21개, 적/오브젝트 스프라이트 65개, savedata semantic 160/1274 bytes, prototype coverage 6개)와 아직 필요한 원본 증거를 나란히 보여주며 `missing 8/8 · prototype coverage 6` 으로 요약한다. `HWANSE_LAST_EVENT_REVIEW_RENDER` 는 `browserEventOriginalProofMatrixImplemented=True`, `eventOriginalProofMatrixRowCount=8`, `eventOriginalProofMatrixMissingRowCount=8`, `eventOriginalProofMatrixPrototypeCoverageCount=6`, `eventOriginalProofMatrixNonPromoting=True`, `eventOriginalProofMatrixFirstGapId=routeLinkedEventVmExecution` 를 남기고, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 event/dialogue/battle partial 범위를 원본 proof gate 별로 명확히 보여주는 UX/증거 분리 보강이며, original event VM runtime, original battle entry, enemy row/stat/reward/formula, story flag proof 로 승격하지 않는다.
- 2026-06-10 dialogue review proof matrix 보강: `web/dialogue_review.html` 에 `대사 proof matrix` 표를 추가해 extracted dialogue blocks, candidate dialogue smoke, dialogue completion restore, branch/control replay, render/literal/input replay, full event VM decode, route-linked event VM execution, original story/battle dispatch 를 8개 gate 로 분리했다. 표는 대사 블록 추출 1개를 grounded, 후보 대사 smoke/완료 복원 2개를 passed, branch/control 및 render/literal/input replay 2개를 partial, full VM decode/route-linked VM/story-battle dispatch 3개를 missing 으로 요약해 `grounded 1 · passed 2 · partial 2 · missing 3` 을 보여준다. `HWANSE_LAST_DIALOGUE_REVIEW_RENDER` 는 `browserDialogueProofMatrixImplemented=True`, `dialogueProofMatrixRowCount=8`, `dialogueProofMatrixGroundedRowCount=1`, `dialogueProofMatrixPassedRowCount=2`, `dialogueProofMatrixPartialRowCount=2`, `dialogueProofMatrixMissingRowCount=3`, `dialogueProofMatrixOriginalVmMissing=True`, `dialogueProofMatrixFirstMissingId=full-event-vm-decode` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 후보 대사 replay 와 원본 event VM/story/battle dispatch gap 을 대사 검토 화면 안에서 분리하는 관리자 UX/증거 보강이다.
- 2026-06-10 menu review original proof matrix 보강: `web/menu_review.html` 에 `원본 menu/system proof matrix` 표를 추가해 original shop runtime, original price/inventory table, original money mutation, original party join event, original party trail runtime, original equipment offsets, original equipment effects, original story flags 를 8개 gate 로 분리했다. 표는 후보 smoke 5/5 passed, 상점 후보 2개/아이템 6개, 동료 합류 2명/follower 2명, savedat skill 6/24, 장비 후보 18개/target item 5개, 상태 멤버 3명을 현재 브라우저 후보 증거로 보여주고, 원본 dispatch/table/offset/runtime writer/story flag 증거는 모두 `missing 8/8` 로 유지한다. `HWANSE_LAST_MENU_REVIEW_RENDER` 는 `browserMenuOriginalProofMatrixImplemented=True`, `menuOriginalProofMatrixRowCount=8`, `menuOriginalProofMatrixMissingRowCount=8`, `menuOriginalProofMatrixCandidateSmokePassedCount=5`, `menuOriginalProofMatrixNonPromoting=True`, `menuOriginalProofMatrixFirstGapId=original-shop-runtime` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 메뉴/상점/장비/상태 후보 구현과 원본 시스템 proof gap 을 분리하는 관리자 UX 보강이며, original shop runtime, equipment offset/effect, combat formula, story flag proof 로 승격하지 않는다.
- 2026-06-10 format review proof matrix 보강: `web/format_review.html` 에 `포맷 proof matrix` 표를 추가해 `GENSE.FLD`, `PCMDATA.WLK`, `MIDDATA.MLK`, CNS image/tile payloads, DirectDraw display, DirectInput/input tables, savedat semantic coverage, event/object VM full decode 를 8개 영역으로 분리했다. 표는 archive/audio/MIDI/CNS/DirectDraw 5개를 grounded, DirectInput/savedata 2개를 partial, event VM full decode 1개를 blocked 로 요약해 `grounded 5 · partial 2 · blocked 1` 을 보여준다. `HWANSE_LAST_FORMAT_REVIEW_RENDER` 는 `browserFormatProofMatrixImplemented=True`, `formatProofMatrixRowCount=8`, `formatProofMatrixGroundedRowCount=5`, `formatProofMatrixPartialRowCount=2`, `formatProofMatrixBlockedRowCount=1`, `formatProofMatrixEventVmBlocked=True` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 binary-format partial 상태를 포맷 영역별로 분리해 보여주는 관리자 UX/증거 보강이며, event VM full instruction/operand decode 또는 route-linked execution proof 로 승격하지 않는다.
- 2026-06-10 format review event VM promotion boundary 보강: `web/format_review.html` 의 opcode coverage 아래에 `event VM promotion boundary` 표를 추가해 브라우저 partial known-opcode replay 와 원본 event VM 승격 gate 를 같은 화면에서 분리했다. 표는 `browser-partial-known-opcode-replay` 1행을 partial 로 보여주고, `fullInstructionLengthDecode`, `fullOperandLayoutDecode`, `routeLinkedEventVmExecution`, `sceneEventDialogueBinding`, `originalStoryFlagMutation`, `fullBrowserEventVmImplementation`, `eventDrivenBattleEntry` 7개 gate 를 모두 missing 으로 보여준다. `HWANSE_LAST_FORMAT_REVIEW_RENDER` 는 `browserFormatVmPromotionBoundaryImplemented=True`, `formatVmPromotionBoundaryRowCount=8`, `formatVmPromotionBoundaryPartialRowCount=1`, `formatVmPromotionBoundaryMissingRowCount=7`, `formatVmPromotionBoundaryRequiredGateRowCount=7`, `formatVmPromotionBoundaryPromotesOriginalVm=False`, `formatVmPromotionBoundaryAllGatesPassed=False`, `eventVmPromotionBoundaryNonPromoting=True` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 DOM/marker 를 검증한다. 이는 2번 바이너리/VM 포맷 추정에서 현재 partial replay 성과와 남은 원본 runtime proof 를 분리해 다음 작업 단위를 명확히 하는 보강이며, full event VM implementation, original story flag mutation, event-driven battle entry, route promotion proof 로 승격하지 않는다.
- 2026-06-10 completion review proof matrix 보강: `web/completion_review.html` 에 `완료 proof matrix` 표를 추가해 confirmed normal progression, browser route completion, browser route clear restore, deep routeAssist chain, route promotion, original full-game ending, completion audit, external required inputs 를 8개 gate 로 분리했다. 표는 browser-local route completion/clear/deep-chain 3개를 passed, confirmed normal progression 1개를 partial, route promotion/external inputs 2개를 blocked, original full-game ending/completion audit 2개를 missing 으로 요약해 `passed 3 · partial 1 · blocked 2 · missing 2` 를 보여준다. `HWANSE_LAST_COMPLETION_REVIEW_RENDER` 는 `browserCompletionProofMatrixImplemented=True`, `completionProofMatrixRowCount=8`, `completionProofMatrixPassedRowCount=3`, `completionProofMatrixPartialRowCount=1`, `completionProofMatrixBlockedRowCount=2`, `completionProofMatrixMissingRowCount=2`, `completionProofMatrixOriginalCompletionMissing=True`, `completionProofMatrixFirstBlockedId=route-promotion` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 후보 완료/클리어가 원본 full-game completion 으로 오인되지 않도록 하는 관리자 UX/증거 분리 보강이며, original ending, route promotion, goal completion audit 으로 승격하지 않는다.
- 2026-06-10 관리 홈/게임 런타임 링크 분리 후속 보강: 관리 홈이 더 이상 게임 런타임을 직접 품지 않으므로 docs/tools/out 의 쿼리형 실행 링크를 `index.html?...` 에서 `game.html?...` 로 정규화했다. `web/game.html` 의 routeAssist in-place 후보 전환도 현재 페이지가 `routeAutoSave=1` 로 시작하지 않았더라도 `activateNextRoutePath()` 가 계산한 href 에 `routeAutoSave=1` 이 있으면 최종 URL, transition snapshot, auto-save payload 에 같은 요청을 보존하도록 고쳤다. 이에 맞춰 `tools/verify_candidate_route_progress_browser.py` 는 title `game.html?game=1` 이어하기 뒤 남는 query parameter 순서에 의존하지 않고 실제 `map/startTile/trialTransitions` 값으로 복원 URL 을 판정한다. 8013 기준 `verify_runtime_http.py`, `verify_web_assets.py`, `verify_home_landing_browser.py`, `verify_title_menu_sound_browser.py`, `verify_runtime_music_cue_browser.py`, `verify_map3_runtime_browser.py`, `verify_route_guide_browser.py`, `verify_candidate_route_progress_browser.py`, tools AST syntax check 를 통과했으며, 중간에 디스크를 채운 Codex TUI 로그만 truncate 해 리포트 작성 공간을 회복했다. 이 변경은 관리 UX/링크 정합성/브라우저-local routeAssist 저장성 보강이며, `goal_completion_checklist` 는 계속 `achieved=false`, route promotion 은 `blocked` 로 남긴다.
- 2026-06-10 관리 홈 일반 웹뷰 재보정: 사용자가 다시 지적한 대로 기본 `web/index.html` 을 게임형 랜딩처럼 보이지 않게 `legacy aggregate asset workbench (removed)` 패턴의 일반 관리 웹뷰로 재배치했다. 보이는 제목은 `환세취호전 관리 홈`, `data-view-mode="admin-web-view"`, 상단은 관리 링크와 검색만 두고 `타이틀 런타임 확인`/`후보 루트 런타임 확인` 은 하단 `보조 검증 도구` 표로 낮췄다. 본문은 `asset-workbench`/`asset-workbench-panel`/`asset-workbench-head` 구조의 `작업 검토 워크벤치` 표와 아래 상태/작업 큐 표로 구성하며, `HWANSE_LAST_HOME_RENDER` 는 `displayMode="admin-web-view"`, `layoutKind="assets-workbench-plain-admin-tables"`, `browserHomeAssetWorkbenchLayout=True`, `browserHomeGameEntryOnlyInMenu=True`, `browserHomeGameEntryDemotedToAdminTools=True`, `browserHomeRuntimeEntryPresentedAsAdminUtility=True`, `browserHomeCanvasRuntime=False` 를 남긴다. `tools/verify_home_landing_browser.py` 는 홈의 정상 `<main>` 을 게임 runtime 으로 오인하지 않고 `#screen`/canvas/script 부재, 상단 요약의 `game.html`/`runtime-entry-table` 미노출, 새 workbench 구조를 확인하도록 고쳤고, `tools/verify_web_assets.py` 는 새 정적 구조/marker 를 강제한다. 이는 관리자 첫 화면 표현 보정이며, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-10 selector review proof matrix 보강: `web/selector_review.html` 에 `셀렉터 proof matrix` 표를 추가해 promotion hard gates, strict source hotspot, real selector `2:0` savedata, selected-root runtime trace, predecessor fill execution, selector merge runtime, opcode20 object selector context, opcode24 mode1 producer 를 8개 gate 로 분리했다. 현재 표는 `blocked 7 · partial 1 · passed 0` 으로 표시되며, opcode20 은 ref 204/object selector 16개까지는 잡혔지만 frontier runtime coverage 가 없어 partial 로 유지하고 나머지는 route promotion hard blocker 또는 selected-root/predecessor/merge/opcode24 proof 부재로 blocked 로 유지한다. `HWANSE_LAST_SELECTOR_REVIEW_RENDER` 는 `browserSelectorProofMatrixImplemented=True`, `selectorProofMatrixRowCount=8`, `selectorProofMatrixBlockedRowCount=7`, `selectorProofMatrixPartialRowCount=1`, `selectorProofMatrixPromotionBlocked=True`, `selectorProofMatrixSelectedRootBlocked=True`, `selectorProofMatrixFirstBlockedId=promotion-hard-gates`, `selectorProofMatrixNonPromoting=True` 를 남긴다. `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 selector/selected-root 증거의 현재 차단 지점을 관리 화면에서 분리해 보여주는 UX/증거 보강이며, selected-root execution proof, captured selector `2:0` savedata, strict hotspot proof, route promotion 으로 승격하지 않는다.
- 2026-06-10 proof review 외부 증거 matrix 보강: `web/proof_review.html` 에 `외부 증거 proof matrix` 표를 추가해 accepted proof records, captured selector `2:0` savedata, normal-route runtime trace, strict source hotspot, selected-root execution, current leaf/wrapper, selector support packets, opcode24 runtime producer, route promotion gate 를 9개 gate 로 분리했다. 현재 표는 `missing 5 · blocked 3 · template-only 1 · accepted 0` 으로 표시되며, validator 는 아직 template-only/accepted record 0개, runtime trace/opcode24/route promotion 은 blocked, captured save/strict hotspot/selected-root/wrapper/selector support 는 missing 으로 남는다. `HWANSE_LAST_PROOF_REVIEW_RENDER` 는 `browserExternalProofMatrixImplemented=True`, `externalProofMatrixRowCount=9`, `externalProofMatrixMissingRowCount=5`, `externalProofMatrixBlockedRowCount=3`, `externalProofMatrixTemplateOnlyRowCount=1`, `externalProofMatrixAcceptedRowCount=0`, `externalProofMatrixRouteBlocked=True`, `externalProofMatrixFirstBlockedId=normal-route-runtime-trace`, `externalProofMatrixNonPromoting=True` 를 남기며, `tools/verify_home_landing_browser.py`/`tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 어떤 외부 입력이 route promotion proof 로 인정되는지 관리 화면에서 더 명확히 보여주는 UX/증거 분리 보강이며, 외부 proof 제출, selected-root execution proof, captured selector `2:0` savedata, strict hotspot proof, route promotion 자체를 대체하지 않는다.
- 2026-06-10 legacy aggregate workbench 직접 필터 진입 보강: `legacy aggregate asset workbench (removed)` 은 이제 `?category=sprite`, `?category=enemy`, `?category=object`, `?q=...`, `?asset=...` URL 파라미터를 읽어 일반 웹 화면처럼 특정 자산 범위와 선택 항목으로 바로 들어갈 수 있다. `자산 워크벤치` 의 몬스터/공격 행은 `65 스프라이트` 링크로 `monster_review.html` 를 제공하고, 선택된 enemy/object preview 는 기존처럼 `monster_review.html?asset=<key>` 로 몬스터/공격 프레임 검토 화면에 연결된다. `removed legacy workbench marker` 는 `browserAssetUrlParamFilterImplemented=True`, `activeCategory`, `filterValue`, `selectedAssetLabel`, 초기 category/query/asset param 을 남긴다. `removed asset workbench browser verifier` 는 8013 기준 `/web/monster_review.html?asset=zk_big` 직접 진입이 `sprite` 필터, `zk` 검색, `zk_big` preview, `monster_review.html?asset=zk_big` 링크를 유지하는지 확인해 `deepLink=17/132` 를 리포트에 남기고, `tools/verify_web_assets.py` 도 같은 smoke/static marker 를 요구한다. 이는 legacy aggregate asset workbench (removed) 에 모인 자산을 몬스터/오브젝트 상세 검토로 더 바로 이어주는 관리자 UX 보강이며, enemy row/stat/reward/formula, original attack sequence, route promotion proof 로 승격하지 않는다.
- 2026-06-10 legacy aggregate workbench 추출 범위 표 보강: `legacy aggregate asset workbench (removed)` 에 `추출 범위 표` 를 추가해 이미지 갤러리 132개, enemy/object 스프라이트 `65/65`(enemy 58/object 7), EXE 스프라이트 descriptor `65 refs / 64 payload refs / gap zky_nmk.cns`, 전투 후보 `8 unique / 21 rows`, 음원 `54 WLK WAV / 20 MLK MIDI` 를 한눈에 보이게 했다. 표는 `monster_review.html`, `monster_review.html`, `original_battle_resource_descriptors.html`, `non_party_descriptor_asset_links.html`, `battle_analysis.html`, `audio_title_provenance.html` 으로 직접 연결하며, `removed legacy workbench marker` 는 `browserAssetCoverageTableImplemented=True`, `assetCoverageRowCount=5`, `assetCoverageSummary`, `assetCoverageText` 를 남긴다. 8013 기준 `removed asset workbench browser verifier` 는 coverage row/link/text/marker 를 실제 브라우저로 검증하고 `removed asset workbench browser smoke` 는 `coverage images=132 sprites=65/65 descriptorPayloads=64/65 audio=54+20` 를 기록한다. `tools/verify_web_assets.py` 도 정적 DOM/marker 와 갱신된 smoke 를 요구한다. 이는 `legacy aggregate asset workbench (removed)` 에서 몬스터가 적어 보이는 혼선을 줄이기 위한 관리자 UX/coverage 보강이며, original enemy rows/stat/reward/formula 또는 route promotion proof 로 승격하지 않는다.
- 2026-06-10 legacy aggregate workbench 음원 제목 출처 요약 보강: `legacy aggregate asset workbench (removed)` 에 `음원 제목 출처 요약` 표를 추가해 WLK/MLK 카드 이름이 embedded title인지 EXE id entry인지 바로 구분하게 했다. `PCMDATA.WLK` 54개는 embedded effect title 저장소가 없어 `embedded 0`, browser cue provenance 9개, EXE id entry 45개로 표시하고, `MIDDATA.MLK` 20개는 MIDI track-name title 16개와 EXE id entry 4개(`MLK id 02`, `MLK id 06`, `MLK id 11`, `MLK id 17`)로 표시한다. 표는 `out/audio_title_provenance.html` 상세 근거로 연결하며, `removed legacy workbench marker` 는 `browserAssetAudioTitleSummaryImplemented=True`, `audioTitleRowCount=2`, `audioTitleWlkBrowserCueLabelCount=9`, `audioTitleWlkFallbackLabelCount=45`, `audioTitleMlkEmbeddedTitleCount=16`, `audioTitleMlkFallbackLabelCount=4`, `audioTitleMlkNoEmbeddedIds=02,06,11,17` 을 남긴다. 8013 기준 `removed asset workbench browser verifier` 와 `tools/verify_web_assets.py` 는 이 DOM/marker/smoke markdown 을 검증한다. 이는 음원 제목 누락처럼 보이는 항목의 출처를 설명하는 관리자 UX 보강이며, original DirectSound/DirectMusic runtime proof 로 승격하지 않는다.
- 2026-06-10 monster review sprite-only 직접 전투 실행 보강: `web/monster_review.html` 은 이제 후보 전투 proximity row 가 붙은 8개뿐 아니라 default scope 의 65개 추출 enemy/object sprite 모두에 `스프라이트 전투 실행` 링크를 제공한다. 링크는 `game.html?battle=1&battleCandidate=sprite-only:<asset>` 형식이며, 후보 row 가 없는 스프라이트도 `extracted-sprite-only-prototype` 전투로 바로 열 수 있다. `HWANSE_LAST_MONSTER_REVIEW_RENDER` 는 `browserMonsterSpriteOnlyBattleLinkImplemented=True`, `spriteOnlyBattleCandidateId`, `spriteOnlyBattleHref`, `spriteOnlyBattleRuntimeSelectableAssetCount=65`, `spriteOnlyBattleDirectLinkSource="monster-review-direct-sprite-link"` 를 남긴다. `tools/verify_home_landing_browser.py` 는 몬스터 검토 DOM 에서 직접 실행 링크와 marker 를 확인하고, `tools/verify_candidate_battle_browser.py` 는 8013 기준 `/web/game.html?map=map2_14j&battle=1&battleCandidate=sprite-only:zk_big` 직접 URL 이 `sprite-only:zk_big`, `enemySprite=zk_big.cns`, `enemyProfileSource=generated-extracted-sprite-profile`, `sourceBacked=False`, `battleStartFeedback=전투 시작 btl_j1` 로 전투 scene 에 진입하는지 `battleSpriteDirectUrl` 로 검증한다. `tools/verify_web_assets.py` 는 이 smoke/static evidence 를 요구한다. 이는 추출된 몬스터/오브젝트 그래픽을 검토 화면에서 즉시 웹 전투 프로토타입으로 열기 위한 gameplay/admin 연결 보강이며, original enemy row/stat/reward/formula, original attack sequence/AI, event-driven battle entry proof 로 승격하지 않는다.
- 2026-06-10 관리 홈 plain web table 재보정: 기본 `web/index.html` 이 게임형 랜딩처럼 보이지 않도록 `legacy aggregate asset workbench (removed)` 패턴을 더 엄격히 적용했다. 헤더는 `진행상황`/`자산`/`완료` 관리자 shortcut 3개와 검색만 남기고, 본문은 `작업 검토 워크벤치`, `빠른 검토 링크`, `다음 작업 큐`, `작업 상태 표`의 일반 관리 표로 구성한다. 기존 카드형 `admin-dashboard`/`panel` 상태 영역은 제거했고, 게임 진입은 헤더나 첫 화면 런타임이 아니라 `game.html?game=1` workbench 표 행으로만 남긴다. `HWANSE_LAST_HOME_RENDER` 는 `layoutKind="assets-workbench-plain-admin-tables"`, `browserHomePlainAdminTables=True`, `browserHomeDashboardCardsRemoved=True`, `browserHomeCanvasRuntime=False`, `browserHomeGameEntryOnlyInWorkbench=True`, `browserHomeHeaderShortcutsOnly=True` 를 남긴다. `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 header game link 0개, status table DOM, no canvas, no runtime script, no dashboard-card 구조를 검증한다. 이는 관리자 첫 화면 표현 보정이며, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-10 map gallery 직접 맵 필터 보강: `web/map_gallery.html` 은 이제 `?map=map1_02b`, `?scope=accepted|all|rejected`, `?q=...` URL 파라미터를 읽어 특정 맵의 CNS 소스/조립 맵/게임 overview 링크로 바로 좁혀 들어갈 수 있다. 검색/범위 변경 시 URL 도 `map` 또는 `q` 기준으로 동기화하며, `HWANSE_LAST_MAP_GALLERY_RENDER` 는 `browserMapGalleryUrlParamFilterImplemented=True`, `activeSearch`, `selectedMapParam`, `directMapFilterMatched`, `directMapSourceHref`, `directMapReviewHref` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 는 기본 174개 맵 목록과 별도로 `/web/map_gallery.html?map=map1_02b&scope=accepted` 직접 진입이 `map1_02b.cns`, accepted 조립 review, game overview 링크 1개로 좁혀지는지 `mapGalleryDirect=map1_02b` 로 검증하고, `tools/verify_web_assets.py` 는 정적 marker 를 요구한다. 이는 맵 소스/완성형 조립 검토에 빨리 접근하기 위한 관리자 UX 보강이며, route promotion 또는 strict hotspot proof 로 승격하지 않는다.
- 2026-06-10 monster review 공격 후보 직접 링크 보강: `web/monster_review.html` 은 이제 `?asset=zk_big&attack=special-or-reaction`, `?scope=all|candidate`, `?q=...` URL 파라미터를 읽어 특정 몬스터와 공격별 프레임 후보로 바로 들어간다. 공격별 프레임 후보 카드에는 `공격 후보 직접 링크` 를 추가하고 선택된 공격 카드를 표시하며, 검색/범위/공격 선택은 URL 과 동기화된다. `HWANSE_LAST_MONSTER_REVIEW_RENDER` 는 `browserMonsterAttackUrlParamImplemented=True`, `selectedAttackId`, `selectedAttackTitle`, `directAttackHref`, `attackSequenceDirectLinkCount`, `attackDeepLinkMatched` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 는 기본 몬스터 검토와 별도로 `/web/monster_review.html?asset=zk_big&attack=special-or-reaction` 직접 진입이 `zk_big` 의 `special-or-reaction` 공격 후보를 선택하고 해당 직접 링크를 유지하는지 `monsterDirect=zk_big:special-or-reaction` 으로 검증하며, `tools/verify_web_assets.py` 는 정적 marker 를 요구한다. 이는 몬스터 이미지/공격 기술/공격 프레임 후보를 더 빠르게 확인하기 위한 관리자 UX 보강이며, original enemy row/stat/reward/formula 또는 original attack sequence/AI proof 로 승격하지 않는다.
- 2026-06-10 monster review 공격 후보 표 보강: `web/monster_review.html` 의 선택 몬스터 상세에 `공격 후보 표` 를 추가해 `primary-command`, `linked-action-text`, `special-or-reaction` 3개 후보를 카드보다 먼저 표로 요약한다. 각 행은 후보명/ID, 전투 텍스트 또는 action/skill table 출처, 프레임 run(`#0..`), 직접 링크, `original attack sequence/AI not proven` 판정을 함께 보여준다. 기존 공격별 프레임 카드와 같은 `attackSequencesFor()` 결과를 재사용하므로 새 추론을 만들지 않고, `HWANSE_LAST_MONSTER_REVIEW_RENDER` 는 `browserMonsterAttackCandidateTableImplemented=True`, `attackCandidateRowCount=3`, `attackCandidateSelectedRowCount=1`, `attackCandidateDirectLinkCount=3`, `attackCandidateFrameRuns` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 는 기본 몬스터 검토와 직접 공격 URL 양쪽에서 표 행/선택 행/직접 링크/비승격 문구를 실제 브라우저로 검증하고, `tools/verify_web_assets.py` 는 정적 DOM/marker 를 요구한다. 이는 몬스터별 공격 기술과 공격 애니메이션 프레임 후보를 더 읽기 쉽게 보여주는 관리자 UX 보강이며, original attack sequence/AI, enemy row/stat/reward/formula proof 로 승격하지 않는다.
- 2026-06-10 map review 소스/조립 비교 표 보강: `web/map_review.html` 의 `source and assembled map` 요약에 `맵 소스/조립 비교 표` 를 추가해 선택 맵의 `extract_fld/<map>.cns`, `out/maps_runtime_chunks/<map>.js`, 소스 타일셋 CNS 링크, accepted 조립 설정, browser overview 링크, 후보/transition 검토 상태를 6개 행으로 한 번에 확인하게 했다. `map1_02b` 기준 표는 grounded 3개, passed 1개, browser-only 1개, partial 1개로 표시되며 `browser-only` 완성형 맵 링크는 visual/layout 확인용이고 route proof 로 승격하지 않는다고 명시한다. `HWANSE_LAST_MAP_REVIEW_RENDER` 는 `browserMapSourceAssemblyTableImplemented=True`, `sourceAssemblyRowCount=6`, `sourceAssemblyLinkCount=7`, `selectedMapSourceCns`, `selectedMapRuntimeChunk`, `selectedMapSourceTilesets`, `selectedMapAssembledGameHref`, `selectedMapAcceptedVisual`, `selectedMapAcceptedTileIndexMode` 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 맵 소스 파일과 완성형 조립 맵을 같이 보고 싶다는 관리자 UX 보강이며, strict hotspot, selector `2:0` savedata, selected-root execution, runtime trace, route promotion proof 를 대체하지 않는다.
- 2026-06-10/11 audio review WLK 직접 진입 보강: `web/audio_review.html` 은 `?wlk=<exeId>` URL 파라미터를 받으면 해당 raw WLK 카드 하나만 바로 연다. 예를 들어 `?wlk=45` 는 `WLK id 45`, raw `../extract_wlk/45.wav`, gain -1800 항목을 직접 보여준다. 각 WLK 카드에는 `audio_review.html?wlk=<id>` 직접 링크를 추가했고, 선택 카드에는 `data-selected-audio="true"` 를 남긴다. 이는 WLK 항목을 더 빨리 확인하기 위한 관리자 UX 보강이며, original DirectSound/WinMM MIDI runtime proof 로 승격하지 않는다.
- 2026-06-10 관리 홈 다음 작업 큐 보강: 기본 `web/index.html` 의 일반 웹 관리 홈에 `다음 작업 큐` 표를 추가해 `out/completion_audit.json` 의 `openNextActions` 7개와 `blockedNextActions` 2개를 첫 화면에서 바로 볼 수 있게 했다. 각 행은 priority, 상태(`외부 증거 대기`/`외부 증거 필요`), task/why, next input summary, evidence ref 링크를 보여주며, 표 header 와 상태 표는 progress 화면과 같은 기준으로 `local 0 / external 9` 를 노출한다. `HWANSE_LAST_HOME_RENDER` 는 `browserHomeActionQueueImplemented=True`, `browserHomeActionDependencySplitImplemented=True`, `openActionCount=7`, `blockedActionCount=2`, `localExecutableActionCount=0`, `externallyConstrainedActionCount=9`, `actionEvidenceLinkCount>=9` 를 남긴다. 여기서 `open` 은 로컬에서 곧바로 route proof 를 끝낼 수 있다는 뜻이 아니라 completion audit 에서 계속 추적할 조사 항목이라는 뜻이며, 현재 홈도 외부 증거 없이 승격 가능한 항목이 0개임을 분리해 보여준다. `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 새 큐 DOM/marker 를 검증한다. 이는 작업이 route blocker 에 매몰되지 않도록 첫 화면에서 다음 조사 단위를 확인하기 위한 관리자 UX 보강이며, selected-root execution, captured selector `2:0` savedata, strict hotspot proof, route promotion 을 대체하지 않는다.
- 2026-06-10 관리 홈 빠른 검토 링크 보강: 기본 `web/index.html` 에 `빠른 검토 링크` 표를 추가해 자산/맵/몬스터/전투/대사/이벤트/세이브/오브젝트/메뉴/음원/진행 검토의 대표 deep link 를 첫 화면에서 바로 열 수 있게 했다. 표는 `monster_review.html?asset=zk_big`, `map_gallery.html?map=map1_02b&scope=accepted`, `map_review.html?map=map1_02b&visualFilter=layer1UnderSceneTilesets&tileIndexFilter=row40_zero`, `format_review.html#vmPromotionBoundaryPanel`, `monster_review.html?asset=zk_big&attack=special-or-reaction`, `audio_review.html?wlk=45`, `audio_review.html#audioRuntimeBoundaryPanel`, `battle_analysis.html?sprite=zk_big`, `dialogue_review.html?block=event-dialogue-block-005`, `event_review.html?type=dialogue&block=event-dialogue-block-005`, `event_review.html#eventRuntimeBoundaryPanel`, `object_position_review.html?save=event-dialogue-block-033&object=0x004e8206`, `menu_review.html?panel=equipment`, `savedata_review.html#savedataOffsetBoundaryPanel`, `progress.html` 15개 링크를 제공한다. `HWANSE_LAST_HOME_RENDER` 는 `browserHomeQuickReviewLinksImplemented=True`, `browserHomeQuickReviewBoundaryLinksImplemented=True`, `browserHomeQuickReviewExecutionBoundaryLinksImplemented=True`, `quickReviewRowCount=15`, 각 direct href marker 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 사용자가 `legacy aggregate asset workbench (removed)` 에서 모든 자산을 한꺼번에 뒤지는 대신 대표 맵 소스/조립, VM promotion 경계, 몬스터 공격 프레임, WLK id 45, 음원 런타임 경계, 전투 스프라이트 후보, 대사/이벤트 후보, 원본 실행 흐름 경계, 세이브/오브젝트 후보, 메뉴/장비 후보, 세이브 오프셋 경계, 작업 분리 상태로 바로 이동하게 하는 관리자 UX 보강이며, original enemy/attack, original event VM execution, original save/object runtime, original menu/equipment runtime, strict hotspot, route promotion proof 로 승격하지 않는다.
- 2026-06-10 관리 홈 전체 목표 로드맵 보강: 기본 `web/index.html` 의 일반 관리 웹뷰에 `전체 목표 로드맵` 표를 추가해 처음 정의한 1~8번 작업 순서를 홈에서도 바로 확인하게 했다. 표는 1/3/4/7번을 complete, 2/5/6/8번을 partial 로 보여주고, 포맷/VM 검토, 외부 증거 검증, 게임 메뉴, 진행상황 화면을 대표 링크로 연결한다. `HWANSE_LAST_HOME_RENDER` 는 `browserHomeWorkOrderRoadmapImplemented=True`, `workOrderRowCount=8`, `workOrderCompleteCount=4`, `workOrderPartialCount=4`, `workOrderRouteProofSeparated=True`, `browserHomeWorkOrderRoadmapNonPromoting=True` 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 홈 DOM/marker 를 검증한다. 이는 메인 랜딩을 게임처럼 보이지 않게 유지하면서 전체 목표 대비 현재 위치를 첫 화면에 드러내는 관리자 UX 보강이며, selected-root execution, captured selector `2:0` savedata, strict hotspot, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-10 관리 홈 런타임 링크 접기 보정: 사용자가 다시 지적한 대로 기본 `web/index.html` 을 `legacy aggregate asset workbench (removed)` 같은 일반 웹뷰로 더 엄격히 맞추기 위해 16개 게임/후보 런타임 실행 링크와 3개 런타임 검증 도구를 `보조 런타임 도구` 닫힌 details 섹션 안으로 내렸다. 홈의 기본 화면은 `작업 검토 워크벤치`, `빠른 검토 링크`, `전체 목표 로드맵`, `다음 작업 큐`, `작업 상태 표`의 관리 표 중심으로 유지하고, 실제 게임 실행은 사용자가 명시적으로 보조 섹션을 펼칠 때만 보이게 했다. `HWANSE_LAST_HOME_RENDER` 는 `runtimeUtilityCollapsed=True`, `browserHomeRuntimeToolsCollapsed=True`, `browserHomeRuntimeToolsPresentedAsCollapsedUtility=True`, `browserHomeCanvasRuntime=False` 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 닫힌 상태와 일반 관리 웹뷰 marker 를 검증한다. 이는 관리자 첫 화면 표현 보정이며, route promotion, selected-root execution, captured selector `2:0` savedata, strict hotspot 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-10 menu review 직접 패널 진입 보강: `web/menu_review.html` 은 이제 `?panel=shop|party|skill|equipment|status|progress|story` 또는 `?menu=...` URL 파라미터를 읽어 `직접 메뉴 후보` 표에서 상점, 동료, 기술, 장비, 상태, 진행, 스토리 후보 중 하나를 선택 표시한다. 각 행은 review URL, 후보 게임 URL, smoke JSON, 브라우저 후보 증거, 원본 gap 을 함께 보여주며 `?panel=equipment` 는 장비 후보 18개/대상 3명/Ataho 5개 item 및 original equipment offsets/effects/combat formula gap 을, `?panel=progress`/`?panel=story` 는 browser-local 진행 기록과 파생 story-state 검토를 바로 드러낸다. 후보 게임 URL 은 `game.html?...&menu=equipment`, `game.html?...&menu=progress`, `game.html?...&menu=story` 같은 직접 런타임 메뉴 실행 파라미터를 사용한다. `web/game.html` 은 `menu=shop|party|skill|equipment|status|progress|story` 또는 `directMenu=...` 를 읽어 맵 로드와 savedat/public save 로드 뒤 해당 후보 메뉴나 대화 검토를 바로 열고 `HWANSE_LAST_DIRECT_MENU_QUERY` 에 `browserRuntimeDirectMenuQueryImplemented=True`, `panel`, `menuMode`, `opened`, `originalMenuRuntimePromoted=False` 를 남긴다. 2026-06-10 후속으로 `menu=save-point`/`directMenu=save-point` alias 도 추가해 `map2_07e` 같은 현재 맵 save-point 후보에서 `save-point-candidate` 메뉴를 바로 열 수 있게 했고, marker 는 `panel=save-point`, `scope=current-map`, `candidateCount=1`, `originalMenuRuntimePromoted=False` 를 남긴다. `HWANSE_LAST_MENU_REVIEW_RENDER` 는 `browserMenuReviewUrlParamImplemented=True`, `menuDirectRowCount=7`, `menuDirectSelectedCount`, `selectedMenuPanelId`, `selectedMenuPanelRuntimeHref`, `progressStoryFlagCount`, `browserMenuProgressStoryReviewImplemented=True`, `menuDirectNonPromoting=True` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 는 기본 메뉴 검토, 직접 장비 review URL, 그리고 `menu=equipment/skill/status/party/shop/save-point/progress/story` 런타임 URL 8개를 실제 브라우저로 검증해 `menuDirect=equipment` 와 `runtimeMenuDirect=equipment:equipment-target,skill:skill-member,status:status-member,party:party-candidate,shop:shop-candidate,save-point:save-point-candidate,progress:dialogue,story:dialogue` 를 리포트에 남기고, `tools/verify_web_assets.py` 는 정적 DOM/marker 를 요구한다. 이는 메뉴/상점/기술/장비/상태/진행/스토리/세이브 후보 진행 상황을 일반 관리 웹뷰와 실제 웹 런타임에서 바로 확인하기 위한 UX/실행 연결 보강이며, original shop runtime, original party join event, original save-point runtime, original equipment offsets/effects, original story flag runtime, route promotion proof 로 승격하지 않는다.
- 2026-06-10 object direct runtime 후속 보강: `web/game.html` 은 이제 `menu=object`/`directMenu=object` 와 `inspect`/`object-candidate`/`조사` alias 를 읽어 현재 맵의 오브젝트 후보 메뉴를 바로 연다. `map2_03l` 기준 marker 는 `panel=object`, `menuMode=object-candidate`, `candidateCount=3`, `originalMenuRuntimePromoted=False`, `originalEventObjectRuntimeImplemented=False` 범위로 남고, `tools/verify_home_landing_browser.py` 는 direct runtime sweep 에 `object:object-candidate` 를 추가로 검증한다. 관리 홈의 `런타임 실행 링크` 표는 이 링크와 confirmed `map1_02b -> map1_01a` 전환 링크를 함께 제공한다. 이는 조사 후보와 confirmed transition prototype 을 일반 관리 웹뷰에서 실행하기 위한 UX/실행 연결이며, original object/NPC runtime, linked dialogue runtime, route promotion proof 로 승격하지 않는다.
- 2026-06-10 battle review 직접 전투 후보 보강: `web/battle_analysis.html` 은 이제 `?sprite=zk_big` 또는 `?candidate=event-dialogue-block-015%3Abtl_b1` 같은 URL 파라미터를 읽어 전투 후보를 직접 표시한다. 새 `직접 전투 후보` 표는 이벤트 전투 후보와 추출 enemy/object sprite 후보를 각각 보여주고, 후보 자체의 direct review 링크, `monster_review.html?asset=<sprite>`, `game.html?map=map2_14j&battle=1&battleCandidate=sprite-only:<sprite>` 실행 링크를 제공한다. 관리 홈 `빠른 검토 링크` 도 `battle_analysis.html?sprite=zk_big` 행을 대표 battle deep link 로 제공한다. `HWANSE_LAST_BATTLE_REVIEW_RENDER` 는 `browserBattleReviewUrlParamImplemented=True`, `battleDirectRowCount=2`, `selectedBattleSpriteKey="zk_big"`, runtime/monster href marker 를 남기고, `HWANSE_LAST_HOME_RENDER` 는 `quickReviewBattleHref="battle_analysis.html?sprite=zk_big"` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 가 기본 battle review 및 direct sprite URL 을 검증한다. 이는 추출된 몬스터/오브젝트 스프라이트를 전투 검토와 prototype battle runtime 으로 바로 이어주기 위한 관리자 UX 보강이며, original battle entry, enemy row/stat, formation, reward/formula proof 로 승격하지 않는다.
- 2026-06-10 monster review 전체 공격 후보 매트릭스 보강: `web/monster_review.html` 에 `전체 공격 후보 매트릭스` 를 추가해 기본 `추출 스프라이트 전체` scope 에서 enemy/object sprite 65개를 모두 행으로 보여주고, 각 행마다 소스 CNS, 주 행동 후보, 연결 액션 후보, 특수/반응 후보, 프레임 그리드 수, `monster_review.html?asset=<sprite>&attack=special-or-reaction` 직접 검토 링크, `game.html?battle=1&battleCandidate=sprite-only:<sprite>` 전투 실행 링크를 제공한다. 기존 단일 몬스터 상세의 `공격 후보 표`/`공격별 프레임 후보`/proof matrix 는 유지하되, 새 marker `HWANSE_LAST_MONSTER_REVIEW_RENDER` 에 `browserMonsterAttackOverviewImplemented=True`, `attackOverviewRowCount=65`, `attackOverviewAttackCandidateCount=195`, `attackOverviewSourceLinkedRowCount=8`, `attackOverviewDirectReviewLinkCount=65`, `attackOverviewBattleLinkCount=65`, `attackOverviewDefaultAllSprites=True` 를 추가했다. 8013 기준 `tools/verify_home_landing_browser.py` 는 실제 DOM 에서 65행/195 후보/65개 검토 링크/65개 전투 링크를 확인하고, `tools/verify_web_assets.py` 는 정적 DOM/marker 를 요구한다. 이는 사용자가 몬스터가 적어 보인다고 느끼지 않도록 추출된 전체 몬스터/오브젝트 스프라이트와 공격 프레임 후보를 한 화면에서 스캔하게 하는 관리자 UX 보강이며, original enemy row/stat, formation, reward/formula, per-enemy AI/attack sequence proof 로 승격하지 않는다.
- 2026-06-11 monster review 추출 범위 표 보강: `web/monster_review.html` 에 `몬스터 추출 범위` 표를 추가해 전체 추출 enemy/object 65개와 source-linked battle candidates 8개/21행을 분리했다. 표는 `all-extracted-enemy-object-sprites`, `enemy-sprite-assets`, `object-sprite-assets`, `battle-review-source-linked`, `original-enemy-row-binding` 5행으로 구성되며, enemy 58개/object 7개/원본 enemy row 승격 0개를 함께 보여준다. 이후 전체 추출 범위 `monster_review.html?scope=all` 과 source-linked 후보 범위 `monster_review.html?scope=candidate` 직접 링크도 추가했다. `HWANSE_LAST_MONSTER_REVIEW_RENDER` 는 `browserMonsterExtractionCoverageImplemented=True`, `monsterCoverageRowCount=5`, status counts, `monsterCoverageExtractedSpriteCount=65`, `monsterCoverageEnemySpriteCount=58`, `monsterCoverageObjectSpriteCount=7`, `monsterCoverageSourceLinkedSpriteCount=8`, `monsterCoverageBattleCandidateRowCount=21`, `monsterCoverageScopeLinkCount=2`, `monsterCoverageAllScopeHref="monster_review.html?scope=all"`, `monsterCoverageCandidateScopeHref="monster_review.html?scope=candidate"`, `monsterCoverageOriginalEnemyRowsBound=False`, `monsterCoverageNonPromoting=True` 를 남긴다. 이는 battle review 후보가 전체 몬스터 목록이 아니라 EXE resource descriptor proximity subset 임을 명확히 하는 관리자 UX 보강이며, original enemy row/stat/reward/formula, original attack sequence/AI, event-driven battle entry 또는 route promotion proof 로 승격하지 않는다.
- 2026-06-10 dialogue/event 직접 후보 진입 보강: `web/dialogue_review.html` 은 `?block=event-dialogue-block-005` 또는 `?dialogueBlock=...` URL 파라미터를 읽어 `직접 대사 블록` 표에서 해당 블록의 분류, 맵, 대표 대사, `event_review.html?type=dialogue&block=<id>`, `game.html?map=map4_08n&dialogue=1&dialogueBlock=<id>` 링크를 바로 보여준다. `web/event_review.html` 도 `?type=dialogue&block=event-dialogue-block-005` 를 읽어 검색/유형 필터를 대사 후보로 맞추고 `직접 이벤트 후보` 표와 선택 카드 marker 를 남긴다. `HWANSE_LAST_DIALOGUE_REVIEW_RENDER` 는 `browserDialogueReviewUrlParamImplemented=True`, `selectedDialogueBlockId="event-dialogue-block-005"`, `selectedDialogueRuntimeHref` 를, `HWANSE_LAST_EVENT_REVIEW_RENDER` 는 `browserEventReviewUrlParamImplemented=True`, `selectedEventBlockId="event-dialogue-block-005"`, `selectedEventDialogueRuntimeHref` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 는 기본 화면과 직접 URL 양쪽에서 `eventDirect=event-dialogue-block-005`, `dialogueDirect=event-dialogue-block-005` 를 실제 브라우저로 검증하고, `tools/verify_web_assets.py`/`tools/verify_runtime_http.py` 도 정적/HTTP 검증을 통과한다. 이는 이미 추출된 대사/이벤트 후보를 관리자 화면에서 바로 확인하기 위한 UX 보강이며, route-linked event VM execution, full event VM implementation, original story flag mutation, route promotion proof 로 승격하지 않는다.
- 2026-06-10 event review 원본 실행 흐름 경계 보강: `web/event_review.html` 에 `원본 실행 흐름 경계` 표를 추가해 event/object dispatch table, text/control opcode subset, browser partial dialogue replay, route-linked dialogue dispatch, event-driven battle entry, original save-point runtime, original object/NPC runtime, original story flag mutation 을 8개 행으로 분리했다. 표는 dispatch/opcode 근거 2개를 grounded, browser partial replay 1개를 passed, 원본 실행/전투/세이브/오브젝트/story mutation 5개를 missing 으로 표시한다. `HWANSE_LAST_EVENT_REVIEW_RENDER` 는 `browserEventRuntimeBoundaryImplemented=True`, `eventRuntimeBoundaryRowCount=8`, `eventRuntimeBoundaryGroundedRowCount=2`, `eventRuntimeBoundaryPassedRowCount=1`, `eventRuntimeBoundaryMissingRowCount=5`, `eventRuntimeBoundaryDispatchTableVaHex="0x0047f1d8"`, `eventRuntimeBoundaryRouteLinkedCommandCount=2`, `eventRuntimeBoundaryRouteLinkedPointerOverlap=True`, `eventRuntimeBoundaryBattleCandidateCount=21`, `eventRuntimeBoundarySaveCandidateCount=8`, `eventRuntimeBoundaryObjectCandidateCount=10`, `eventRuntimeBoundaryNonPromoting=True` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 DOM/marker 를 검증한다. 이는 5번 원본 실행 흐름 분석에서 이미 확인된 dispatcher/opcode/replay 증거와 아직 없는 원본 event/battle/save/object/story runtime 증거를 분리하는 관리자 UX/증거 경계 보강이며, route-linked event VM execution, original battle entry, original save-point/object runtime, original story mutation, route promotion proof 로 승격하지 않는다.
- 2026-06-10 save/object 직접 후보 진입 보강: `web/object_position_review.html` 은 `?save=event-dialogue-block-033&object=0x004e8206` URL 파라미터를 읽어 `직접 세이브/오브젝트 후보` 표에서 세이브 후보 블록과 object branch 후보 VA 를 함께 선택 표시한다. 세이브 후보 행은 `dialogue_review.html?block=event-dialogue-block-033`, `event_review.html?type=dialogue&block=event-dialogue-block-033`, `game.html?map=map2_07e`, source 링크를 제공하고, 오브젝트 후보 행은 `0x004e8206`/`0x25`/handler label 과 source 링크를 보여주며 선택 상태에서도 `non-promoting` 을 함께 표시한다. `HWANSE_LAST_OBJECT_REVIEW_RENDER` 는 `browserObjectReviewUrlParamImplemented=True`, `objectDirectRowCount=2`, `objectDirectSelectedCount=2`, `selectedSavePointBlockId="event-dialogue-block-033"`, `selectedObjectCandidateVaHex="0x004e8206"`, `selectedObjectCandidatePromotesRoute=False` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 는 기본 object review 와 직접 URL 양쪽을 실제 브라우저로 검증해 `objectDirect=event-dialogue-block-033:0x004e8206` 를 리포트에 남기고, `tools/verify_web_assets.py`/`tools/verify_runtime_http.py` 도 정적/HTTP 검증을 통과한다. 이는 세이브포인트/오브젝트 후보를 관리자 화면에서 바로 확인하기 위한 UX 보강이며, original save-point runtime, original event-object runtime, original linked-dialogue runtime, current-route object proof, route promotion proof 로 승격하지 않는다.
- 2026-06-10 진행상황 원래 작업 순서 로드맵 보강: `web/progress.html` 에 사용자가 처음 정의한 1~8번 작업 순서(`파일 인벤토리 분석`, `바이너리 포맷 추정`, `리소스 추출기 작성`, `이미지/팔레트/사운드 뷰어 작성`, `원본 실행 흐름 분석`, `웹 Canvas 런타임 구현`, `첫 화면 또는 맵 한 장 재현`, `입력/이동/대화/전투 기능 확장`)를 별도 표로 노출했다. 표는 현재 완료 4개/부분 4개로 표시하고 각 행마다 대표 산출물과 다음 조건을 붙인다. 특히 2/5/6/8번은 계속 진행 가능한 partial 이지만, 5번의 route-linked event VM/battle entry/selected-root execution proof 와 6/8번의 original proof gap 은 route promotion 으로 승격하지 않는다고 분리한다. `HWANSE_LAST_PROGRESS_RENDER` 는 `browserOriginalWorkOrderRoadmapImplemented=True`, `originalWorkOrderRowCount=8`, `originalWorkOrderCompleteCount=4`, `originalWorkOrderPartialCount=4`, `originalWorkOrderFormatPartial=True`, `originalWorkOrderRuntimePartial=True`, `originalWorkOrderFeatureExpansionPartial=True`, `originalWorkOrderRouteProofSeparated=True` 를 남기고, 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 가 DOM/marker 를 검증한다. 이는 작업이 특정 route blocker 에 매몰되지 않도록 원래 목표 순서와 현재 partial 범위를 진행상황 화면에서 직접 확인하기 위한 관리자 UX 보강이며, completion audit `achieved=false` 와 route promotion `blocked` 는 유지한다.
- 2026-06-10 format review 세이브 포맷 coverage 보강: `web/format_review.html` 이 `out/savedata_sample_coverage.json` 과 `out/savedata_sample_deltas.json` 을 직접 읽어 `세이브 포맷 coverage` 표를 보여준다. 표는 save size/semantic coverage, public sample selector coverage, route-critical offsets, unknown varying ranges, unsupported original systems 5개 행으로 나뉘며 현재 `known 160/1274`, known semantic fields 94, unknown varying ranges 87, sample count 6, current selector `2:0` public sample 0, route pair public sample 0, route-critical offsets 11, expected missing row 1, unsupported original systems 3개를 표시한다. `savedata-format` proof row 도 하드코딩 대신 coverage/delta 값으로 `known semantic bytes=160/1274` 와 route-critical offset count 를 표시한다. `HWANSE_LAST_FORMAT_REVIEW_RENDER` 는 `browserFormatSavedataCoverageImplemented=True`, `savedataFormatCoverageRowCount=5`, `savedataCoverageExpectedSize=1274`, `savedataCoverageKnownSemanticBytes=160`, `savedataCoverageKnownSemanticFieldCount=94`, `savedataCoverageUnknownVaryingRangeCount=87`, `savedataCoverageSampleCount=6`, `savedataCoverageCurrentSelector="2:0"`, `savedataCoverageCurrentSelectorPublicSampleCount=0`, `savedataCoverageRoutePairPublicSampleCount=0`, `savedataCoverageRouteCriticalOffsetCount=11`, `savedataCoverageRouteCriticalExpectedMissingCount=1`, `savedataCoverageUnsupportedOriginalSystemCount=3`, `savedataCoveragePromotesRoute=False` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 가 DOM/marker 를 검증한다. 이는 로드맵 2번 바이너리/세이브 포맷 추정의 partial 상태를 포맷 화면에서 직접 확인하게 하는 증거 연결 보강이며, real selector `2:0` savedata, selected-root execution, strict hotspot proof 로 승격하지 않는다.
- 2026-06-10 format review event VM opcode coverage 보강: `web/format_review.html` 이 이제 `out/event_vm_opcode_semantics.json` 을 직접 읽어 `event VM opcode coverage` 표를 보여준다. 표는 handler-grounded opcode 16개(`0x02`, `0x03`, `0x04`, `0x06`, `0x07`, `0x08`, `0x09`, `0x0a`, `0x0b`, `0x0c`, `0x0d`, `0x0e`, `0x15`, `0x1b`, `0x35`, `0x37`)의 handler VA, decoded length/variable length, operand/effect, browser replay 여부, non-promoting 판정을 opcode별로 노출한다. 현재 browser replay subset 은 4개(`0x02`, `0x0b`, `0x0d`, `0x35`), variable-length row 는 `0x08` 1개, literal storage marker 는 `0x35` 1개이고, `0x0c` route-linked hit 는 pointer overlap 로 계속 비승격이다. `HWANSE_LAST_FORMAT_REVIEW_RENDER` 는 `browserFormatOpcodeCoverageImplemented=True`, `formatOpcodeCoverageRowCount=16`, `formatOpcodeCoverageBrowserReplayRowCount=4`, `formatOpcodeCoverageVariableLengthRowCount=1`, `formatOpcodeCoverageLiteralStorageRowCount=1`, `formatOpcodeCoverageDispatcherVerified=True`, `eventVmOpcodeDispatcherTableVaHex="0x0047f1d8"`, `eventVmOpcode0cPointerOverlapNotPromoted=True`, `eventVmOpcodeFullVmPromoted=False` 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 로드맵 2번 바이너리/VM 포맷 추정에서 어느 opcode가 실제 근거를 갖는지 한 화면에 고정하는 관리자 UX/증거 보강이며, full instruction length/operand layout, route-linked event VM execution, original story flag mutation, event-driven battle entry proof 로 승격하지 않는다.
- 2026-06-10/11 format review 오디오 런타임 경계 보강: `web/format_review.html` 이 `out/audio_archive_manifest.json`, `out/audio_title_provenance.json`, `out/midi_bgm_test_browser_smoke.json`, `out/runtime_music_cue_browser_smoke.json`, `out/title_menu_sound_browser_smoke.json`, `removed asset workbench browser smoke` 을 함께 읽어 `오디오 런타임 경계` 표를 보여준다. 표는 `PCMDATA.WLK` 54개 PCM, `MIDDATA.MLK` 20개 SMF0 MIDI, WLK title provenance, MLK title provenance, browser browser cues, MLK soundfont scheduling, original DirectSound runtime, original WinMM MIDI playback 을 분리한다. 여기서 WLK title storage 는 `absent`, WLK runtime/fallback label 은 `9/45`, MLK embedded/fallback label 은 `16/4`, runtime music cue 와 title menu sound smoke 는 `passed`, original DirectSound/WinMM runtime 은 `false` 로 유지한다. `HWANSE_LAST_FORMAT_REVIEW_RENDER` 는 `browserFormatAudioRuntimeBoundaryImplemented=True`, audio manifest/soundfont markers, `formatAudioRuntimeBoundaryNonPromoting=True`, `originalDirectSoundRuntimeImplemented=False`, `originalDirectMusicPlaybackImplemented=False` 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 로드맵 2번 바이너리/오디오 포맷 확정과 브라우저 오디오 cue 구현의 경계를 포맷 화면에서 직접 확인하게 하는 증거 연결 보강이며, original DirectSound mixer/timing/loop proof, original WinMM MIDI playback/selection proof, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-10 format review CNS payload 경계 보강: `web/format_review.html` 에 `CNS payload 경계` 표를 추가해 CNS compression stream, CNS image payloads, CNS tile-index payloads, compact tilemap header variant, field map assembly surface, battle background tilemaps, tilemap second-plane semantics, original collision/event semantics 를 8개 행으로 분리했다. `out/cns_payloads.json` 기준 전체 377개, image 177개, tilemap 200개, field map tile payload 174개, battle background tilemap 26개, map tileset image 45개, 4bpp image 80개, 8bpp image 97개, compact header variant 1개(`map0_01n.cns`)를 표시하며, 현재 grounded 4, passed 2, partial 1, missing 1 로 요약한다. 특히 field map assembly 와 battle background tilemap은 웹 검토/조립 표면으로 passed 이지만, tilemap second plane 의 정확한 원본 draw semantics 는 partial, original collision/event/transition semantics 는 missing 으로 유지한다. `HWANSE_LAST_FORMAT_REVIEW_RENDER` 는 `browserFormatCnsPayloadBoundaryImplemented=True`, `formatCnsPayloadBoundaryRowCount=8`, `formatCnsPayloadBoundaryGroundedRowCount=4`, `formatCnsPayloadBoundaryPassedRowCount=2`, `formatCnsPayloadBoundaryPartialRowCount=1`, `formatCnsPayloadBoundaryMissingRowCount=1`, `cnsImage4bppCount=80`, `cnsImage8bppCount=97`, `cnsMapTilesetImageCount=45`, `cnsCompactHeaderVariantCount=1`, `cnsBattleTilemapCount=26`, `cnsPayloadBoundaryNonPromoting=True`, `cnsOriginalCollisionEventSemanticsMissing=True` 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 로드맵 2번 CNS 포맷 추정에서 payload decode 와 원본 collision/event semantics 를 분리해 보여주는 증거 연결 보강이며, original collision, event trigger, transition proof, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-10 format review Win32/DirectX 런타임 경계 보강: `web/format_review.html` 이 `out/exe_imports.json`, `out/directdraw_flow.json`, `out/input_keymap.json`, `out/runtime_timing.json`, `out/runtime_movement.json`, audio smoke 를 함께 읽어 `Win32/DirectX 런타임 경계` 표를 보여준다. 표는 PE import surface, DirectDraw display mode/presentation, DirectInput keyboard state tables, GetTickCount main-loop timing, browser runtime mapping, browser audio cue surface, original draw order/dirty rects, original runtime parity 8개 행으로 나뉘며 현재 grounded 4, passed 1, partial 2, missing 1, non-promoting 으로 요약한다. 여기서 `DDRAW.dll`/`DINPUT.dll`/`DSOUND.dll`/`WINMM.dll`/`MSVFW32.dll` import, `DirectDrawCreate`/`DirectInputCreateA`/`DirectSoundCreate`, 640x480x8 DirectDraw surface, DirectInput keyboard state `0x0055b868`, 2개 16-action key table, GetTickCount 48ms loop, browser 192ms tile step 은 근거로 표시하지만, original DirectSound mixer, original draw order/dirty-rect scheduling, full original runtime parity 는 partial/missing 으로 유지한다. `HWANSE_LAST_FORMAT_REVIEW_RENDER` 는 `browserFormatWin32RuntimeBoundaryImplemented=True`, `formatWin32RuntimeBoundaryRowCount=8`, `formatWin32RuntimeBoundaryGroundedRowCount=4`, `formatWin32RuntimeBoundaryPassedRowCount=1`, `formatWin32RuntimeBoundaryPartialRowCount=2`, `formatWin32RuntimeBoundaryMissingRowCount=1`, `win32ImportDllCount=9`, `directInputKeyboardStateVaHex="0x0055b868"`, `runtimeTimingFrameIntervalMs=48`, `runtimeMovementWebTileStepMs=192`, `browserRuntimeMappingNonPromoting=True`, `originalDrawOrderDirtyRectsComplete=False`, `originalRuntimeParityImplemented=False` 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 로드맵 2/5번의 바이너리 포맷·원본 실행 흐름 근거를 일반 관리 화면에 묶어 보여주는 보강이며, selected-root execution, captured selector `2:0` savedata, strict hotspot, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-10 format review DirectDraw 호출 시퀀스 보강: `web/format_review.html` 에 `DirectDraw 호출 시퀀스` 표를 추가해 `out/directdraw_flow.json` 의 25개 vtable call 을 VA, interface/method, vtable offset, role/notes, verified 상태로 그대로 표시한다. 현재 25/25 calls 가 verified 이며 메서드 분포는 `Blt` 6, `Flip` 1, `CreateSurface` 4, palette 계열(`CreatePalette`/`SetPalette`/`SetEntries`/`GetEntries`) 6개다. 표에는 `SetCooperativeLevel`, `SetDisplayMode`, `CreateSurface`, `CreateClipper`, `SetHWnd`, `SetClipper`, `CreatePalette`, `SetPalette`, `SetEntries`, `GetEntries`, `Flip`, `Blt` 의 VA 범위가 렌더되고, `HWANSE_LAST_FORMAT_REVIEW_RENDER` 는 `browserFormatDirectDrawCallSequenceImplemented=True`, `formatDirectDrawCallSequenceRowCount=25`, `formatDirectDrawCallSequenceVerifiedRowCount=25`, `directDrawBltCallCount=6`, `directDrawFlipCallCount=1`, `directDrawCreateSurfaceCallCount=4`, `directDrawPaletteCallCount=6`, `directDrawCallSequenceNonPromoting=True`, `directDrawDirtyRectOrderingComplete=False` 를 남긴다. `tools/verify_home_landing_browser.py` 는 8013 기준 실제 DOM 에서 row/method/VA 를 확인하고, `tools/verify_web_assets.py` 는 정적 구조와 marker 를 검증한다. 이는 로드맵 5번 원본 DirectDraw 실행 흐름 분석의 확인 가능한 call surface 를 관리 화면에 고정하는 보강이며, full original draw ordering, dirty-rect invalidation, surface composition, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 DirectDraw 문서 보강: `docs/DIRECTDRAW_NOTES.md` 에 `Verified Call Sequence` 절을 추가해 같은 25개 DirectDraw vtable call 을 순서대로 문서화하고, 메서드 카운트(`Blt` 6, `Flip` 1, `CreateSurface` 4, palette 계열 6)와 남은 질문을 명시했다. 남은 질문은 각 `Blt` 호출의 whole-surface/dirty-rect/windowed scaling 역할 분리, surface wrapper table 과 sprite/object draw record 연결, `Flip` path 와 windowed `Blt` path 를 mode flags `0x004676d4`/display selector `0x004676ec` 와 대조하는 것이다. 이는 `format_review.html` 의 관리 표와 원문 분석 문서를 같은 evidence surface 로 맞추는 작업이며, full draw-order proof 나 route promotion 으로 승격하지 않는다.
- 2026-06-11 format review DirectDraw draw-order gap 보강: `web/format_review.html` 에 `DirectDraw draw-order gap` 표를 추가해 surface wrapper setup, palette update path, presentation call sites, browser presentation boundary, copy/update vs windowed `Blt` roles, full draw order and composition 을 6개 행으로 분리했다. 현재 grounded 3, passed 1, partial 1, missing 1 로 요약하며, `copy/update Blt=3`, `windowed/scaled Blt=3` 은 식별됐지만 whole-surface copy/dirty-rect/windowed scaling 역할 분리와 sprite/object draw record ordering 은 아직 missing/partial 로 유지한다. `HWANSE_LAST_FORMAT_REVIEW_RENDER` 는 `browserFormatDirectDrawDrawOrderGapImplemented=True`, `formatDirectDrawDrawOrderGapRowCount=6`, `formatDirectDrawDrawOrderGapGroundedRowCount=3`, `formatDirectDrawDrawOrderGapPassedRowCount=1`, `formatDirectDrawDrawOrderGapPartialRowCount=1`, `formatDirectDrawDrawOrderGapMissingRowCount=1`, `directDrawCopyUpdateBltCallCount=3`, `directDrawWindowedScaledBltCallCount=3`, `directDrawDrawOrderGapNonPromoting=True`, `directDrawFullCompositionProofFound=False` 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 DirectDraw call surface 와 full renderer proof gap 을 한 화면에서 분리하기 위한 원본 실행 흐름 분석 보강이며, full draw-order proof, dirty-rect invalidation proof, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 작업 전환/인수인계 문서화: 사용자가 KST 08:00 이후 새 작업을 멈추고 정리로 전환하라고 요청했으므로 `docs/HANDOFF.md` 를 추가했다. 문서는 현재 KST 운영 기준, 8013 고정 포트, 실제 `achieved=false`/`routePromotionStatus=blocked` 상태, hard missing evidence 5개, external input 3개, 최신 Win32/DirectX/DirectDraw format review 보강, 마지막 통과 검증 명령, touched files, 다음 로컬 작업 후보, 08:00 KST wrap checklist 를 한곳에 모은다. 이 문서는 다음 AI 또는 사용자가 현재 상태를 빠르게 이어받기 위한 운영 자료이며, active goal 의 실제 완료 감사나 route promotion proof 를 대체하지 않는다.
- 2026-06-11 progress evidence handoff 표 보강: `web/progress.html` 에 `증거 경계/인수인계` 표를 추가해 로컬에서 확인된 근거 18개와 외부 입력이 필요한 근거 4개를 분리 표시한다. 로컬 행은 관리 홈/게임 진입 분리, 홈 보조 런타임 실행 링크, event VM opcode coverage, 맵 소스/조립 커버리지, 충돌/타일 클래스 커버리지, Win32/DirectX 런타임 경계, event VM promotion boundary, 원본 실행 흐름 경계, 원본 런타임 플레이백 경계, WLK/MLK 복원 확정, 세이브 의미/오프셋 경계, system save/equipment/status offset boundary, 렌더러/투영 경계, DirectDraw 25-call sequence, 전투 적 공격 HUD/검토 링크, 몬스터 전투 후보 역링크, 전투 수치/공식 경계, `docs/HANDOFF.md` 수동 전환 문서이고, 외부 행은 hard blocker set, real selector `2:0` captured savedata, selected-root runtime trace, strict source coordinate/tile hotspot 이다. 경계 행 6개는 `format_review.html#vmPromotionBoundaryPanel`, `event_review.html#eventRuntimeBoundaryPanel`, `audio_review.html#audioRuntimeBoundaryPanel`, `savedata_review.html#savedataOffsetBoundaryPanel`, `system_review.html`, `movement_review.html#rendererProjectionBoundaryPanel` 로 직접 연결되고, 런타임 행은 `web/index.html#runtimeUtilityDetails` 에서 16개 browser-local runtime link 와 non-promoting 경계를 확인하게 하며, VM opcode 행은 `web/format_review.html#opcodeCoveragePanel` 에서 16 opcode rows/browser replay 4/dispatcher verified 상태를 확인하게 하고, 맵/충돌/전투/몬스터/수치/오디오 행은 `web/map_gallery.html`/`web/collision_review.html`/`web/battle_analysis.html`/`web/monster_review.html`/`web/audio_review.html` 에서 map source coverage 6행, collision coverage 174 maps/97.77%/1090 gaps, 12행 proof matrix, runtime HUD/link 증거, source-linked battle review link 8개, numeric boundary 6행, WLK/MLK title provenance 와 audio archive manifest 를 확인하게 한다. `HWANSE_LAST_PROGRESS_RENDER` 는 `browserProgressEvidenceHandoffImplemented=True`, `progressEvidenceHandoffRowCount=22`, `progressEvidenceHandoffLocalRowCount=18`, `progressEvidenceHandoffExternalRowCount=4`, `progressEvidenceHandoffBoundaryRowsIncluded=True`, `progressEvidenceHandoffBoundaryRowCount=6`, `progressEvidenceHandoffPlayableSlicesIncluded=True`, `progressEvidenceHandoffPlayableSlicesHref="index.html#runtimeUtilityDetails"`, `progressEvidenceHandoffFormatOpcodeCoverageIncluded=True`, `progressEvidenceHandoffFormatOpcodeCoverageHref="format_review.html#opcodeCoveragePanel"`, `progressEvidenceHandoffMapSourceCoverageIncluded=True`, `progressEvidenceHandoffMapSourceCoverageHref="map_gallery.html"`, `progressEvidenceHandoffCollisionTileCoverageIncluded=True`, `progressEvidenceHandoffCollisionTileCoverageHref="collision_review.html"`, audio archive restoration link, `progressEvidenceHandoffBattleReviewRowsIncluded=True`, `progressEvidenceHandoffMonsterReviewLinksIncluded=True`, `progressEvidenceHandoffBattleNumericBoundaryIncluded=True`, `progressEvidenceHandoffSystemOffsetBoundaryIncluded=True`, `progressEvidenceHandoffBattleReviewHref="battle_analysis.html"`, `progressEvidenceHandoffSystemOffsetBoundaryHref="system_review.html"`, `progressEvidenceHandoffNextInputCount=3`, `progressEvidenceHandoffHardMissingCount=5`, `progressEvidenceHandoffRouteBlocked=True`, `progressEvidenceHandoffGoalAchieved=False`, `progressEvidenceHandoffDirectDrawRowsIncluded=True`, `progressEvidenceHandoffHandoffDocLinked=True` 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 수동/다음 AI 전환 때 로컬 산출물과 외부 proof 요구를 한 화면에서 확인하게 하는 진행 관리 보강이며, goal 실제 완료나 route promotion 으로 승격하지 않는다.
- 2026-06-11 system review save/equipment/status offset boundary 보강: `web/system_review.html` 에 `세이브 장비/상태 오프셋 경계` 표를 추가해 known editor save fields, selector `2:0` route-critical gap, equipment ownership offsets, equipment effect prototype runtime, status flag offsets, story/event flag runtime 을 6행으로 분리했다. 현재 `grounded 1 · passed 1 · partial 1 · missing 3` 이며, known semantic bytes 는 `160/1274`, unknown varying ranges 는 87, equipment evidence 는 `offsets-unmapped` 로 표시한다. `HWANSE_LAST_SYSTEM_REVIEW_RENDER` 는 `browserSystemOffsetBoundaryTableImplemented=True`, `systemOffsetBoundaryRowCount=6`, status counts, `systemOffsetBoundaryKnownSemanticByteCount=160`, `systemOffsetBoundaryUnknownVaryingRangeCount=87`, `systemOffsetBoundaryEquipmentEvidenceStatus="offsets-unmapped"`, `systemOffsetBoundaryNonPromoting=True` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 가 DOM/marker 를 검증한다. 이는 장비/상태 후보 UI와 원본 save offset gap 을 한 화면에서 구분하기 위한 관리자 evidence surface 보강이며, original equipment/status/story offsets, runtime writer proof, captured selector `2:0` savedata, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 관리 홈 최근 검증 작업 표 보강: `web/index.html` 에 일반 관리 표 형태의 `최근 검증된 작업` 섹션을 추가해 방금 검증된 progress handoff, map source/assembly coverage, collision/tile class coverage, event VM opcode coverage, battle proof matrix, asset workbench split, WLK/MLK 복원 확정, battle runtime review link, monster review backlink, battle numeric/formula boundary, system save/equipment/status offset boundary 를 11행으로 노출한다. 대표 링크는 `progress.html#evidenceHandoffPanel`, `map_gallery.html`, `collision_review.html`, `format_review.html#opcodeCoveragePanel`, `battle_analysis.html`, `legacy aggregate asset workbench (removed)`, `audio_review.html`, `battle_analysis.html?candidate=event-dialogue-block-015%3Abtl_b1`, `monster_review.html`, `battle_analysis.html`, `system_review.html` 이며, quick review 진행 행과 progress handoff 는 `local 18 / external 4` 를 남긴다. `HWANSE_LAST_HOME_RENDER` 는 `browserHomeRecentVerifiedWorkImplemented=True`, `browserHomeRecentWorkAdminTable=True`, `browserHomeRecentWorkLinksImplemented=True`, `recentWorkRowCount=11`, `recentWorkProgressHref`, `recentWorkMapSourceCoverageHref`, `recentWorkCollisionCoverageHref`, `recentWorkFormatOpcodeHref`, `recentWorkBattleReviewHref`, `recentWorkAssetsHref`, `recentWorkAudioTitleHref`, `recentWorkBattleRuntimeHref`, `recentWorkMonsterReviewHref`, `recentWorkBattleNumericHref`, `recentWorkSystemOffsetHref` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 가 DOM/marker 를 검증한다. 이는 사용자가 관리 홈에서 최근 작업 진행과 검증 위치를 바로 알 수 있게 하는 관리자 UX 보강이며, 게임풍 랜딩으로 되돌리지 않고 original event VM execution, original collision route proof, original audio playback parity, original enemy AI, route promotion, completion audit 완료로 승격하지 않는다.
- 2026-06-11 관리 홈 자산 분리 현황 표 보강: `web/index.html` 에 `자산 분리 현황` 표를 추가해 홈에서 바로 맵 소스 파일, 조립 완료 맵, 몬스터 이미지 소스, 몬스터 공격 프레임, 전투 수치/공식 근거, 음원 제목 출처를 6행으로 확인하게 했다. 핵심 링크는 `../extract_fld/map1_02b.cns`, `map_review.html?map=map1_02b&visualFilter=layer1UnderSceneTilesets&tileIndexFilter=row40_zero`, `monster_review.html?asset=zk_big`, `monster_review.html?asset=zk_big&attack=special-or-reaction`, `../out/original_battle_numeric_context.html`, `../out/audio_title_provenance.html` 이다. `HWANSE_LAST_HOME_RENDER` 는 `browserHomeAssetSplitStatusImplemented=True`, `browserHomeAssetSplitAdminTable=True`, `browserHomeAssetSplitLinksImplemented=True`, `assetSplitRowCount=6`, 각 asset split href marker 를 남기며, `tools/verify_home_landing_browser.py` 콘솔/리포트는 `assetSplitRows=6` 을 기록한다. 이는 `legacy aggregate asset workbench (removed)` 처럼 일반 웹 관리 표로 분리 현황을 보는 UX 보강이며, route execution, enemy AI, combat formula, playback parity 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 legacy aggregate workbench 맵/몬스터 워크벤치 분리는 cleanup 이후 active surface 에서 제거했다. 맵 소스는 `../extract_fld/map1_02b.cns`, 조립 완료 맵은 `map_review.html?map=map1_02b&visualFilter=layer1UnderSceneTilesets&tileIndexFilter=row40_zero`, 충돌은 `collision_review.html`, 몬스터는 `monster_review.html` 및 `battle_analysis.html` 로 직접 확인한다. 이는 original route execution, enemy AI, battle parity 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 battle runtime 적 공격 후보 HUD/검토 링크 보강: `web/game.html` 전투 런타임의 적 HP 패널 아래에 현재 적 스프라이트, 선택된 공격 후보, frame run 을 표시하는 소형 HUD 를 추가했다. 새 marker `HWANSE_LAST_BATTLE_ENEMY_ATTACK_REVIEW` 는 `source="battle-enemy-attack-review-hud"`, `browserBattleEnemyAttackReviewHudImplemented=True`, `prototypeMonsterAttackFrameRuntimeImplemented=True`, `originalAttackSequenceBound=False`, `originalEnemyAiImplemented=False`, `originalCombatFormulaImplemented=False` 를 남긴다. 또한 전투 scene 에서 `battleReviewLink`/`monsterReviewLink` 를 노출해 현재 후보를 `battle_analysis.html?candidate=event-dialogue-block-015%3Abtl_b1`, 현재 몬스터/공격 후보를 `monster_review.html?asset=zky_ao&attack=primary-command` 로 바로 열 수 있게 했다. 새 marker `HWANSE_LAST_BATTLE_REVIEW_LINKS` 는 `source="battle-runtime-review-links"`, `browserBattleRuntimeReviewLinksImplemented=True`, `visible=True`, `originalEventDrivenBattleEntry=False`, `originalEnemyAiImplemented=False` 를 남긴다. 8013 기준 `tools/verify_candidate_battle_browser.py` 는 pointer-driven battle attack 중 이 marker 들을 검증하며, `out/candidate_battle_browser_smoke.json` 에서 예시 `action=primary-command`, `title=할퀴기`, `frames=[0,1,2,3]`, `asset=zky_ao`, review href 2개를 확인했다. 이는 로드맵 6/8번의 플레이 가능한 전투 프로토타입에서 추출 몬스터 공격 프레임이 실제로 어떤 후보로 쓰이는지 화면과 검증 marker, 관리자 검토 링크에 노출하기 위한 runtime UX 보강이며, original enemy AI, original attack sequence, original combat formula, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 battle review 런타임 HUD/링크 증거 매트릭스 보강: `web/battle_analysis.html` 이 `out/candidate_battle_browser_smoke.json` 의 `snapshots.pointerBattleCommand.enemyAttackReview` 와 `battleReviewLinks` 를 읽어 `전투 proof matrix` 에 `browser-enemy-attack-review-hud`, `battle-runtime-review-links` 2개 passed 행을 추가했다. 매트릭스는 10행에서 12행으로 늘고 요약은 `grounded 2 · passed 6 · candidate 1 · missing 3` 이며, `HWANSE_LAST_BATTLE_REVIEW_RENDER` 는 `browserBattleEnemyAttackReviewHudVerified=True`, `battleEnemyAttackReviewAsset="zky_ao"`, `battleEnemyAttackReviewActionId="primary-command"`, `battleEnemyAttackReviewFrames="0,1,2,3"`, `battleRuntimeReviewLinksVerified=True`, `battleRuntimeReviewLinkHref="battle_analysis.html?candidate=event-dialogue-block-015%3Abtl_b1"`, `battleRuntimeMonsterReviewLinkHref="monster_review.html?asset=zky_ao&attack=primary-command"` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 DOM/marker 를 검증하며, 홈 브라우저 smoke 는 `battle_analysis.html?sprite=zk_big` sprite direct 와 `battle_analysis.html?candidate=event-dialogue-block-015%3Abtl_b1` candidate direct 를 모두 방문해 `selectedBattleSpriteKey="zk_big"` 및 `selectedBattleCandidateId="event-dialogue-block-015:btl_b1"` 를 확인한다. candidate direct 행은 `out/battle_enemy_candidates.json` 의 nearest-resource descriptor 매핑을 사용해 `selectedBattleCandidateEnemyAssetKey="zky_ao"` 와 `selectedBattleCandidateMonsterHref="monster_review.html?asset=zky_ao&attack=primary-command"` 도 남기므로 이벤트 전투 후보에서 몬스터 공격 프레임 검토로 바로 이어진다. 이는 게임 런타임에 새로 붙인 적 공격 HUD/검토 링크를 일반 관리자 전투 검토 화면의 evidence surface 로 끌어올리는 보강이며, original enemy AI, original attack sequence binding, original combat formula, event-driven battle entry, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-11 movement review 렌더러/투영 경계 보강: `web/movement_review.html` 에 `렌더러/투영 경계` 표를 추가해 tile/camera draw projection, dirty-rect helper consumer, party actor draw projection, source rect selector cadence, browser interpolation overlay, DirectDraw composition gap, original sub-tile interpolation 을 7개 행으로 분리했다. 현재 grounded 4, browser-only 1, partial 1, missing 1 로 요약하며, draw projection 함수 `0x00424a2a`, dirty-rect helper target `0x00424cd6`, bounds helper `0x00416ce2`, projected fields `+0x1c/+0x20/+0x24/+0x28`, party actor projection, `+0x28` source rect selector cadence 는 근거화하지만, 브라우저 보간은 overlay 로 유지하고 DirectDraw composition/full dirty-rect scheduling 과 original sub-tile interpolation writer/timing 은 partial/missing 으로 유지한다. `HWANSE_LAST_MOVEMENT_REVIEW_RENDER` 는 `browserMovementRendererProjectionBoundaryImplemented=True`, `movementRendererBoundaryRowCount=7`, `movementRendererBoundaryGroundedRowCount=4`, `movementRendererBoundaryBrowserOnlyRowCount=1`, `movementRendererBoundaryPartialRowCount=1`, `movementRendererBoundaryMissingRowCount=1`, `movementRendererBoundaryDrawRectHelperVaHex="0x00424cd6"`, `movementRendererBoundaryDrawRectBoundsVaHex="0x00416ce2"`, `movementRendererBoundaryProjectedDrawXFieldHex="+0x1c"`, `movementRendererBoundaryProjectedDrawYFieldHex="+0x20"`, `movementRendererBoundaryProjectedFrameSelectorFieldHex="+0x28"`, `movementRendererBoundaryDirectDrawCompositionPartial=True`, `movementRendererBoundaryOriginalSubtileMissing=True`, `movementRendererBoundaryNonPromoting=True` 를 남기며, `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 는 8013 기준 DOM/marker 를 검증한다. 이는 movement projection 근거와 format review DirectDraw composition gap 을 연결하는 관리자 UX/증거 보강이며, full renderer parity, original interpolation proof, route promotion 또는 completion audit 완료로 승격하지 않는다.
- 2026-06-10 transition review route promotion failed gate 표 보강: `web/transition_review.html` 이 `out/route_promotion_gate.json` 을 직접 읽어 `route promotion failed gates` 표를 추가했다. 표는 `strictSourceHotspot`, `tileHotspotConfirmation`, `realSelector20Savedata`, `selectedRootExecution`, `runtimeTraceOrEquivalent` 5개 gate 를 필수 조건/누락 증거/근거 요약/판정으로 보여주며, 긴 gate evidence 는 화면에서 읽을 수 있도록 축약 표시한다. `HWANSE_LAST_TRANSITION_REVIEW_RENDER` 는 `browserTransitionRoutePromotionGateRowsImplemented=True`, `routePromotionGateRowCount=5`, `routePromotionGateBlockedRowCount=5`, `routePromotionGateMissingEvidenceCount=5`, `routePromotionGateStatus="blocked"`, `routePromotionGateAllowed=False`, `routePromotionGateSourceMap="map1_01a"`, `routePromotionGateTargetMap="map2_02d"`, `routePromotionGateStrictSourceHotspotBlocked=True`, `routePromotionGateRealSelectorSavedataBlocked=True`, `routePromotionGateRuntimeTraceBlocked=True` 를 남긴다. 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 가 DOM/marker 를 검증한다. 이는 전환/출구 검토 화면에서 어떤 증거가 route promotion 을 막는지 바로 확인하기 위한 관리자 UX/증거 연결 보강이며, routeAssist frontier, selector scene-list adjacency, geometry exits 를 normal route proof 로 승격하지 않는다.
- 2026-06-10 proof review 외부 증거 intake 경로 보강: `web/proof_review.html` 에 `외부 증거 intake 경로` 표를 추가해 `out/route_promotion_external_proof_template.json` 의 required input 3개와 `out/route_promotion_external_proof_handoff.json` 의 proof package 정보를 한 화면에 합쳤다. 표는 `real-selector-2-0-save`, `normal-route-runtime-trace`, `strict-source-hotspot` 각각의 제출/검색 위치, accepted signal, report/slot scan/web scan/review packet 링크, refresh/scan command 를 보여준다. 특히 captured savedata 는 `SAVEDATA/savedat1.dat .. savedat9.dat`, `SaveData/savedat1.dat .. savedat9.dat`, zip 슬롯, `SAVEDATA/README.md`, `SaveData/README.md`, `game.html?savedatScan=1`, `python3 tools/refresh_savedata_route_proof.py --search-root <file-or-dir-or-zip>` 를 같은 row 에 노출한다. `HWANSE_LAST_PROOF_REVIEW_RENDER` 는 `browserProofIntakeGuideImplemented=True`, `proofIntakeRowCount=3`, `proofIntakeCommandCount>=3`, `proofIntakePathCount>=10`, `proofIntakeWebScanLinkCount>=1`, `proofIntakeSavedataPathVisible=True`, `proofIntakeSaveDataReadmeVisible=True` 를 남기고, 8013 기준 `tools/verify_home_landing_browser.py` 와 `tools/verify_web_assets.py` 가 DOM/marker 를 검증한다. 이는 hard blocker 입력을 실제 작업 폴더/검증 명령으로 연결하기 위한 관리자 UX 보강이며, accepted external proof record 가 없으므로 route promotion 과 completion audit 은 계속 blocked/`achieved=false` 다.

## 참고

- 빌드일 1999-02-11, MSVC 컴파일 → 심볼/RTTI 없음. 압축 루틴은 보통 작은 inline 함수.
- DirectDraw 사용 → 8/16비트 서피스. 팔레트는 보통 256색 RGB 768B.
- 한국 컴파일(Compile Korea?) 작품인 `compile.cns` 등으로 미루어 보아 일본 컴파일 작품의 한국어판 이식.
