feat(algo): 레퍼런스 경로를 dev 스위치로 · 기본은 현행 유지

신 저장소에 맞춘 레퍼런스(piezo-phantom-test/vesiscan_test) 단계들을 옮기되,
demo-final 의 기본 동작은 건드리지 않았다. 2026-09-03 임상이 현재 HEAD 위에서
돌았으므로 그 값을 움직이는 변경을 기본 경로에 넣을 수 없다.

`AlgoMode.reference` (계측 화면 dev 패널 → "알고리즘", 기본 꺼짐) 를 켜면:

  · CCC 3단계 → 7단계
    envelope(①.9) · ant_tiebreak(①) · Λ-dip(①.7) · edge_post(①.8) ·
    lumen_return(①.95) · NTV(② Rule A 만) · fp_gate(③). inward_post 는 빠진다.
  · 파이프라인 4개 추가
    scale_recovery(2) · missing_outside 산출(4) · channel_confidence→untrusted(5b) ·
    CONF_DEMOTE(6). missing_outside 는 CCC **앞**에서 계산한다 — CCC 가 복구한
    채널은 방광 밖이 아니다.
  · BV
    si_floor/missing_outside 로 극 cap clamp 의 방향(상한/하한)을 관측 증거로 가름,
    bottom cap 제한 신설, 중앙 채널 보간 은행가 반올림,
    adaptive_large_bladder_relax 제거(b_si 를 0.85·a_ap 로 바닥 처리해 cap 축 비를
    정확히 0.85 로 만들어 바로 다음 cap 축 폴백을 경계에서 막고 있었다).

검출 파라미터(d_max 15 · inward_walk_win 4) · ANT_FLOOR_REF · cap 축 폴백 ·
ELLIPSE_CAP_R_MAX · TOP_CAP_EDGE_K · cap_d_adaptive · 프리셋 유도 dps/delay 는
ebddc52/20a48ad 에서 이미 기본 경로에 들어가 있어 양쪽 공통이다. 되돌리지 않았다.

검증
  · 기존 경로 무변경 — LegacyEquivalenceDumpTest 가 44 cycle × CCC on/off 를
    검출→BV 로 돌려 덤프하고, HEAD 코드 덤프와 대조. 88 행 전부 일치.
    (이 테스트는 일부러 AlgoMode 를 참조하지 않는다 — HEAD 에 없는 타입이라
     참조하면 대조 자체가 불가능해진다.)
  · 토글 배선 — AlgoModeSwitchTest: 켜면 44 중 40 cycle 이 갈리고
    missing_outside 가 산출되며, 끄면 기존 값이 정확히 재현된다.
  · 전체 30개 통과.

함께 고친 것

저장소가 갈리며 없어진 픽스처 경로(medilightv2android/data123)를
vesiscan-design-archive/data123 로 옮겼다. 5개 테스트가 FileNotFoundException 으로
조용히 실패하고 있었다.

그래서 ebddc52 이후 한 번도 안 돌던 CenterAlignerValidationTest 가 다시 돌았고
hit 7→8 · 10→11 로 어긋났다. 현행 레퍼런스 AnchorGuide(ver='v1') 를 같은 세션에
직접 돌려 보니 8 · 11 이었다 — 코틀린이 맞고 기대값이 낡은 것이다(구
v3_python_reference.py 기준, 현재 저장소에 없음). 기대값을 갱신했다.
bv_cv 는 현행 레퍼런스가 더 이상 내지 않아 대조할 수단이 없다. "Python 과
bit-exact" 라던 주석은 근거가 없어졌으므로 걷어내고 회귀 고정으로 성격을 바꿨다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 17:31:58 +09:00
parent c7f9cc976e
commit ccb44f0ea6
16 changed files with 1268 additions and 88 deletions
@@ -0,0 +1,46 @@
/*
* 알고리즘 경로 전환 — 기존(demo-final 현행) vs 레퍼런스(piezo-phantom-test 1:1).
*/
package com.medithings.vesiscan.managers
/**
* 검출·BV 알고리즘을 어느 쪽으로 돌릴지.
*
* ## 왜 두 경로를 유지하나
* demo-final 은 팬텀 시연과 임상 계측이 함께 도는 브랜치다. 여기서 "기존"이란
* **오늘 임상이 실제로 돌아간 코드**(커밋 `ebddc52`·`20a48ad` 시점의 검출·BV)를 말한다.
* 그 위에 신 저장소가 추가로 맞춘 레퍼런스 단계들은 값을 눈에 띄게 바꾸므로, 시연·계측이
* 모르는 사이 다른 알고리즘으로 도는 일이 없도록 **기본은 기존 경로**로 두고 레퍼런스
* 경로는 dev 패널에서 명시적으로 켤 때만 쓴다.
*
* ## 무엇이 갈리나
* 켜면 아래가 전부 레퍼런스 동작으로 바뀐다. 부분 적용은 없다 — 단계들이 서로를
* 전제하므로 섞으면 어느 쪽도 아닌 값이 나온다.
*
* · 교차채널 보정 3단계 → **7단계**
* (①.9 envelope · ① ant_tiebreak · ①.7 Λ-dip · ①.8 edge ·
* ①.95 lumen_return · ② NTV[Rule A 만] · ③ fp_gate,
* 기존의 `inward_post` 는 빠진다)
* · 파이프라인 `scale_recovery`(2) · `missing_outside` 증거 산출(4) ·
* `channel_confidence`→untrusted(5b) · `CONF_DEMOTE`(6)
* · BV 극 cap 의 상한/하한을 관측 증거로 가르는 `si_floor`/`missing_outside`,
* bottom cap 제한 신설, 중앙 채널 보간 은행가 반올림,
* `adaptive_large_bladder_relax` 제거(cap 축 폴백을 가로막고 있었다)
*
* 검출 파라미터(`d_max` 15 · `inward_walk_win` 4)와 prominence 기준(`ANT_FLOOR_REF`),
* cap 축 폴백 · `ELLIPSE_CAP_R_MAX` · `TOP_CAP_EDGE_K` · `cap_d_adaptive`, 프리셋 유도
* dps/delay 는 **양쪽 공통**이다 — `ebddc52`/`20a48ad` 에서 이미 기존 경로에 들어갔고
* 오늘 임상이 그 위에서 돌았으므로 여기서 되돌리지 않는다.
*
* ## 상태 보관
* 프로세스 수명 동안만 유지한다(런타임 토글). 앱을 다시 켜면 기존 경로로 돌아간다.
*/
object AlgoMode {
/** true = 레퍼런스 1:1 경로. 기본은 false(기존 경로). */
@Volatile
var reference: Boolean = false
/** 화면에 표시할 이름. */
val label: String get() = if (reference) "레퍼런스 (Python 1:1)" else "기존 (현행 임상)"
}