From 57b8779110fede4385afdff2bc75f0134acf3dea Mon Sep 17 00:00:00 2001 From: jjangddu Date: Tue, 29 Sep 2026 17:23:46 +0900 Subject: [PATCH] =?UTF-8?q?ui(align):=20=EC=A7=80=EC=8B=9C=EB=AC=B8?= =?UTF-8?q?=EC=9D=84=20"=EC=B9=98=EA=B3=A8=20=EC=9C=84=20N=20cm=20?= =?UTF-8?q?=EC=97=90=20=EB=B6=99=EC=9D=B4=EA=B3=A0=20=EC=B8=A1=EC=A0=95"?= =?UTF-8?q?=20=ED=95=98=EB=82=98=EB=A1=9C=20=E2=80=94=20=EC=83=81=EB=8C=80?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99(=EC=98=AC=EB=A6=AC=EA=B3=A0/=EB=82=B4?= =?UTF-8?q?=EB=A6=AC=EA=B3=A0)=EC=9D=84=20=EB=BA=80=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 현장 의견(2026-09-29): 판정 뒤 "최적 N cm" 옆에 "아래로 2cm 내리세요" 가 붙어 나와 어디에 붙이라는 건지 헷갈린다. 2026-09-09 에 "최적 위치/부착 위치" 두 숫자가 헷갈려 상대 이동으로 바꿨는데, 상대 이동도 판정 숫자와 나란히 보이면 다시 숫자가 둘이 된다. 치골은 손으로 짚는 기준점이라 **치골 위 절대 위치 하나**만 말한다. 버튼의 숫자 ("N cm 측정하기")와 같아 서로를 확인해 주고, 셀 것도 비교할 것도 없다. 수집 치골 위 N cm 에 붙이고 측정 확인 측정 치골 위 N cm 에 다시 붙이고 측정 (이미 그 자리면 "에서 한 번 더 측정") 확정 치골 위 N+1 cm 에 붙이세요 — 재지 말고 좌우로 재부착 더 아래에 다시 붙이세요 (갈 자리가 없어 이것만 상대적) 화살표(↑↓●)는 남긴다 — 글에는 방향을 쓰지 않고 눈으로만 거든다. 좌우 단계 안내도 "1cm 올린 자리" 대신 "치골 위 N cm 에 붙인 그대로" 로. 시험: AlignInstructionTest 문구 갱신 + "재부착 말고는 상대 이동을 말하지 않는다" 추가. docs/CLINICAL_ALGORITHM.md §3.6 흐름을 새 문구로. Co-Authored-By: Claude Fable 5.1 --- .../ui/views/clinical/AnchorAlignView.kt | 103 +++++++++--------- .../ui/views/clinical/AlignInstructionTest.kt | 42 ++++--- docs/CLINICAL_ALGORITHM.md | 15 ++- 3 files changed, 91 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/com/medithings/vesiscan/ui/views/clinical/AnchorAlignView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/clinical/AnchorAlignView.kt index 222e1a4..2337316 100644 --- a/app/src/main/java/com/medithings/vesiscan/ui/views/clinical/AnchorAlignView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/clinical/AnchorAlignView.kt @@ -13,21 +13,23 @@ * cycle 수가 곧 trace 수를 정하는데(20 → 11 trace), trace 가 줄면 CH3 검출률의 해상도가 * 거칠어져 0.8 임계가 불안정해진다. * - * ## 화면은 지시문 하나만 보여준다 + * ## 화면은 지시문 하나만 보여준다 — 숫자는 "치골 위 N cm" 하나뿐 * 위치 이름(최적·부착)을 쓰지 않는다. 시험하는 사람이 두 숫자를 계속 헷갈렸다 * (2026-09-09 현장) — 둘 다 "위치"라는 이름의 숫자이고 단계마다 다른 쪽이 커졌기 - * 때문이다. 프로브를 잡은 사람에게 필요한 것은 **지금 할 동작 하나**다([instructionOf]). + * 때문이다. 그래서 한때 상대 이동("2cm 내리고 측정")으로 바꿨는데, 그것도 헷갈렸다 + * (2026-09-29 현장: "최적 N cm" 옆에 "아래로 2cm" 가 붙어 다시 숫자가 둘이 됐다). + * 지금은 **치골 위 절대 위치 하나**만 말한다([instructionOf]). 치골이 기준점이라 + * 간호사가 세지 않아도 되고, 버튼의 숫자와 같아 서로를 확인해 준다. * - * 카드(동작) 버튼(자리) - * 치골 바로 위에 붙이고 측정 [0cm 측정하기] - * 1cm 올리고 측정 [1cm 측정하기] + * 카드(자리) 버튼(자리) + * 치골 위 0cm 에 붙이고 측정 [0cm 측정하기] + * 치골 위 1cm 에 붙이고 측정 [1cm 측정하기] * ... - * 2cm 내리고 측정 [1cm 측정하기] - * 여기서 한 번 더 측정 [1cm 측정하기] - * **1cm 올리세요 (재지 말고 좌우로)** — 버튼 없음 + * 치골 위 1cm 에 다시 붙이고 측정 [1cm 측정하기] (확인 측정) + * 치골 위 1cm 에서 한 번 더 측정 [1cm 측정하기] (이미 그 자리) + * **치골 위 2cm 에 붙이세요 (재지 말고 좌우로)** — 버튼 없음 * - * 카드는 **어떻게 움직일지**, 버튼은 **움직인 뒤 어디를 재는지**다. 둘 다 숫자를 쓰면 - * 서로를 확인해 준다 — 카드대로 움직였으면 버튼의 숫자가 지금 자리와 맞는다. + * 화살표(↑↓●)는 지금 자리에서 어느 쪽인지 눈으로만 거든다 — 글에는 방향을 쓰지 않는다. * * 마지막 +1cm 자리는 **측정하지 않는다**. 설계상 그 자리는 지표가 나쁘므로, 재확인하면 * 반드시 "미달"이 떠서 도달 전에 멈추게 된다. @@ -685,13 +687,12 @@ fun AnchorAlignView(appState: AppState) { } Spacer(Modifier.height(16.dp)) - // 지금 무엇을 할지 — 크게. **위치 이름을 쓰지 않는다.** + // 지금 어디에 붙일지 — 크게. **숫자는 "치골 위 N cm" 하나.** // - // 종전에는 "지금 측정할 위치 2cm" 과 "부착 위치 3cm" 을 번갈아 보여 줬다. - // 두 숫자가 다 "위치"라는 이름을 달고 나오니, 시험하는 사람이 어느 자리에 - // 붙여야 하는지 매번 헷갈렸다(2026-09-09 현장 피드백). 실제로 필요한 것은 - // **지금 할 동작 하나**다 — 1cm 올려서 재라, 2cm 내려서 재라, 1cm 올리고 - // 좌우로 넘어가라. 절대 위치는 기록의 몫이고 사람이 셀 일이 아니다. + // 종전에는 "지금 측정할 위치 2cm" 과 "부착 위치 3cm" 을 번갈아 보여 줬고 + // (2026-09-09: 둘 다 "위치"라 헷갈림), 그 다음엔 "2cm 내리고 측정" 같은 상대 + // 이동으로 바꿨다(2026-09-29: "최적 N cm" 과 나란히 보여 다시 헷갈림). 치골을 + // 기준으로 한 절대 위치 하나만 말하면 셀 것도 비교할 것도 없다([instructionOf]). // ── 단일 pass 와 비교 (감사용) ────────────────────────────────── // 앱이 쓰는 값은 전수 판정이다. 단일 pass 가 냈을 답을 같이 보여 주면 // "단봉 가정이 얼마나 깨지는가"를 현장에서도 세어 볼 수 있다. @@ -800,14 +801,10 @@ fun AnchorAlignView(appState: AppState) { enabled = isConnected && !measuring, modifier = Modifier.fillMaxWidth().height(52.dp), shape = RoundedCornerShape(14.dp), - // 카드와 버튼이 역할을 나눈다: **카드는 동작(상대), 버튼은 자리(절대).** - // - // 카드 "1cm 올리고 측정" ← 프로브를 어떻게 움직일지 - // 버튼 "1cm 측정하기" ← 움직인 뒤 어디를 재는지 - // - // 한때 버튼을 "여기서 측정"으로 두었는데 "여기"가 어디인지 알 수 - // 없다는 피드백이 왔다(2026-09-10). 둘 다 숫자를 쓰면 서로를 확인해 - // 준다 — 카드대로 움직였으면 버튼의 숫자가 지금 자리와 맞는다. + // 카드와 버튼이 같은 숫자를 말한다: 카드 "치골 위 1cm 에 붙이고 측정", + // 버튼 "1cm 측정하기". 한때 버튼을 "여기서 측정"으로 두었는데 "여기"가 + // 어디인지 알 수 없다는 피드백이 왔다(2026-09-10). 둘 다 숫자를 쓰면 + // 서로를 확인해 준다 — 카드대로 붙였으면 버튼의 숫자가 지금 자리와 맞는다. ) { Text("${cm}cm 측정하기", fontSize = 16.sp, fontWeight = FontWeight.Bold) } // 수집을 중단하는 문. 두 경우를 한 버튼으로 덮는다: @@ -1105,7 +1102,8 @@ private fun LateralSection( .padding(10.dp) ) { Text( - "앞에서 1cm 올린 자리 그대로 둡니다. 아직 안 올렸으면 지금 올리세요.", + anchorCm?.let { "치골 위 ${it}cm 에 붙인 그대로 둡니다. 아직이면 지금 치골 위 ${it}cm 에 붙이세요." } + ?: "앞에서 정한 자리 그대로 둡니다.", fontSize = 13.sp, fontWeight = FontWeight.SemiBold, color = MlPrimary, ) } @@ -1244,21 +1242,23 @@ private fun RecordRow( } /** - * 화면에 띄울 **지시문 하나**. 위치 이름을 쓰지 않는다. + * 화면에 띄울 **지시문 하나**. 숫자는 "치골 위 N cm" 하나뿐이고 방향은 글에 쓰지 않는다. * - * 시험하는 사람이 "최적 위치"와 "부착 위치"를 계속 헷갈렸다(2026-09-09 현장). 당연하다 — - * 둘 다 "위치"라는 이름의 숫자이고, 화면이 단계마다 다른 쪽을 크게 보여 줬다. 그런데 - * 프로브를 잡은 사람에게 필요한 것은 **지금 할 동작 하나**다. 절대 cm 은 기록의 몫이다. + * 시험하는 사람이 "최적 위치"와 "부착 위치"를 계속 헷갈렸다(2026-09-09 현장) — 둘 다 + * "위치"라는 이름의 숫자였다. 그래서 상대 이동("2cm 내리고 측정")으로 바꿨는데 그것도 + * 헷갈렸다(2026-09-29 현장) — 판정 결과 "N cm" 옆에 "아래로 2cm" 가 붙어 다시 숫자가 + * 둘이 됐다. 치골은 손으로 짚는 기준점이라 **치골 위 절대 위치** 하나면 셀 것이 없다. + * 화살표는 지금 자리에서 어느 쪽인지 눈으로만 거든다. * * | 상태 | 지시 | * |---|---| - * | 첫 측정 전 | 치골 바로 위에 붙이고 측정 | - * | 탐색 중 | N cm 올리고 측정 | - * | best 를 지나침 | N cm 내리고 측정 | - * | 확정 | 1cm 올리고 **재지 말고** 좌우로 | - * | 재부착 | 더 아래(치골 쪽)에 다시 붙이기 | + * | 첫 측정 전 | 치골 위 0cm 에 붙이고 측정 | + * | 탐색 중 | 치골 위 N cm 에 붙이고 측정 | + * | 판정된 자리로 | 치골 위 N cm 에 다시 붙이고 측정 (이미 그 자리면 "에서 한 번 더 측정") | + * | 확정 | 치골 위 N+오프셋 cm 에 붙이세요 — **재지 말고** 좌우로 | + * | 재부착 | 더 아래(치골 쪽)에 다시 붙이기 — 갈 자리가 없어 이것만 상대적이다 | * - * @param nextCm 화면이 다음에 재려는 위치. 호출부가 판정 뒤 이미 갱신해 둔다. + * @param nextCm 화면이 다음에 재려는 위치(치골 위 cm). 호출부가 판정 뒤 이미 갱신해 둔다. */ internal data class AlignInstruction( val arrow: String, @@ -1284,22 +1284,25 @@ internal fun instructionOf( needReattach: Boolean = false, ): AlignInstruction = when { step == null -> AlignInstruction( - "●", "치골 바로 위에 붙이고 측정", + "●", "치골 위 0cm 에 붙이고 측정", "젤을 바르고, 프로브를 치골 바로 위에 밀착시킵니다.") - // 확인 측정까지 끝났다 — 올리고 좌우로. 이 자리는 재지 않는다. - confirmDone -> AlignInstruction( - "↑", "${offsetCm}cm 올리세요", - "여기서는 측정하지 않습니다. 올린 뒤 좌우 맞추기로 넘어갑니다.", - done = true) + // 확인 측정까지 끝났다 — 오프셋 자리에 붙이고 좌우로. 그 자리는 재지 않는다. + confirmDone -> { + val attach = (confirmTarget ?: step.record?.cm ?: nextCm) + offsetCm + AlignInstruction( + "↑", "치골 위 ${attach}cm 에 붙이세요", + "여기서는 측정하지 않습니다. 붙인 뒤 좌우 맞추기로 넘어갑니다.", + done = true) + } - // 수집 중에는 판정이 뭐라 하든 계속 올린다. 판정은 다 재고 나서 한다. + // 수집 중에는 판정이 뭐라 하든 다음 자리로 간다. 판정은 다 재고 나서 한다. sweeping -> AlignInstruction( - "↑", "1cm 올리고 측정", + "↑", "치골 위 ${nextCm}cm 에 붙이고 측정", decidedAtCm?.let { - "${AnchorConfig.SEARCH_MAX_CM}cm 까지 전부 잽니다. " + + "0~${AnchorConfig.SEARCH_MAX_CM}cm 를 전부 잽니다. " + "(옛 방식이면 ${it}cm 에서 멈췄을 자리입니다 — 지금은 다 재고 판정합니다.)" - } ?: "${AnchorConfig.SEARCH_MAX_CM}cm 까지 전부 잽니다.") + } ?: "0~${AnchorConfig.SEARCH_MAX_CM}cm 를 전부 잽니다.") // 다 쟀는데 후보가 하나도 없다. needReattach -> AlignInstruction( @@ -1307,22 +1310,22 @@ internal fun instructionOf( "잰 위치 중 CH3 이 제대로 잡힌 곳이 없습니다. 치골 쪽으로 내려 다시 부착한 뒤 " + "[처음부터 다시 정렬] 을 눌러 주세요.") - // 판정된 자리로 이동 → 확인 측정. + // 판정된 자리로 이동 → 확인 측정. 화살표만 방향을 거든다. confirmTarget != null -> { val from = step.record?.cm ?: confirmTarget val delta = confirmTarget - from when { - delta > 0 -> AlignInstruction("↑", "${delta}cm 올리고 측정", + delta > 0 -> AlignInstruction("↑", "치골 위 ${confirmTarget}cm 에 다시 붙이고 측정", "잰 위치 전부로 고른 자리입니다. 여기서 확인 측정 한 번 합니다.") - delta < 0 -> AlignInstruction("↓", "${-delta}cm 내리고 측정", + delta < 0 -> AlignInstruction("↓", "치골 위 ${confirmTarget}cm 에 다시 붙이고 측정", "잰 위치 전부로 고른 자리입니다. 여기서 확인 측정 한 번 합니다.") - else -> AlignInstruction("●", "여기서 한 번 더 측정", + else -> AlignInstruction("●", "치골 위 ${confirmTarget}cm 에서 한 번 더 측정", "옮겨 온 자리의 상태를 확인하는 마지막 측정입니다.") } } // 여기까지 오면 아직 한 위치도 못 쟀거나 상태가 어긋난 것이다. - else -> AlignInstruction("↑", "1cm 올리고 측정", null) + else -> AlignInstruction("↑", "치골 위 ${nextCm}cm 에 붙이고 측정", null) } /** diff --git a/app/src/test/java/com/medithings/vesiscan/ui/views/clinical/AlignInstructionTest.kt b/app/src/test/java/com/medithings/vesiscan/ui/views/clinical/AlignInstructionTest.kt index 19a8319..47c3b55 100644 --- a/app/src/test/java/com/medithings/vesiscan/ui/views/clinical/AlignInstructionTest.kt +++ b/app/src/test/java/com/medithings/vesiscan/ui/views/clinical/AlignInstructionTest.kt @@ -13,12 +13,15 @@ import org.junit.Test /** * 정렬 화면 지시문. * - * ## 두 가지를 고정한다 + * ## 세 가지를 고정한다 * **① 위치 이름이 화면에 나오면 안 된다.** 시험하는 사람이 "최적 위치"와 "부착 위치"를 * 계속 헷갈렸다(2026-09-09 현장) — 둘 다 "위치"라는 이름의 숫자이고 화면이 단계마다 다른 * 쪽을 크게 보여 줬기 때문이다. 여기서는 **헷갈림 자체가 고치려던 결함**이라 문구가 * 요구사항이다. * + * **① ′ 상대 이동("올리고/내리고")도 나오면 안 된다.** 2026-09-29 현장: 판정 "N cm" 옆에 + * "아래로 2cm" 가 붙어 다시 숫자가 둘이 됐다. 지시는 **치골 위 절대 위치 하나**다. + * * **② 단계 순서.** 2026-09-10 부터 흐름이 바뀌었다: * * 0~4cm 전부 측정 → 전 위치로 판정 → 그 자리로 이동해 확인 측정 → +1cm → 좌우 @@ -61,10 +64,10 @@ class AlignInstructionTest { // ── 수집 단계 ─────────────────────────────────────────────────────────── - @Test fun `수집 중에는 계속 올리라고만 한다`() { + @Test fun `수집 중에는 다음 자리를 치골 위 절대 위치로 말한다`() { val i = instructionOf(step(0), nextCm = 1, offsetCm = 1, sweeping = true) assertEquals("↑", i.arrow) - assertEquals("1cm 올리고 측정", i.headline) + assertEquals("치골 위 1cm 에 붙이고 측정", i.headline) assertTrue("어디까지 재는지 말해야 멈추지 않는다", i.sub!!.contains("${AnchorConfig.SEARCH_MAX_CM}cm")) assertFalse(i.done) @@ -76,7 +79,7 @@ class AlignInstructionTest { // 안 나온다. val i = instructionOf(step(2, searching = false, bestCm = 0), nextCm = 3, offsetCm = 1, sweeping = true, decidedAtCm = 1) - assertEquals("1cm 올리고 측정", i.headline) + assertEquals("치골 위 3cm 에 붙이고 측정", i.headline) assertTrue(i.sub!!.contains("1cm")) assertTrue(i.sub!!.contains("옛 방식")) assertNoPositionWords(i) @@ -88,17 +91,18 @@ class AlignInstructionTest { val i = instructionOf(step(2, searching = false, bestCm = 0), nextCm = 3, offsetCm = 1, sweeping = true, confirmTarget = 0) assertEquals("↑", i.arrow) - assertEquals("1cm 올리고 측정", i.headline) + assertEquals("치골 위 3cm 에 붙이고 측정", i.headline) } // ── 확인 측정 단계 ────────────────────────────────────────────────────── @Test fun `판정된 자리로 내려가 확인 측정하라고 한다`() { - // 4cm 까지 다 재고, 전 위치 판정이 1cm 이면 3cm 내려야 한다. + // 4cm 까지 다 재고, 전 위치 판정이 1cm 이면 치골 위 1cm 에 다시 붙인다. 방향은 + // 화살표만 — 글에 "3cm 내리고" 를 쓰면 판정 숫자와 이동 숫자가 나란히 보여 헷갈린다. val i = instructionOf(step(4, searching = false, bestCm = 0), nextCm = 1, offsetCm = 1, confirmTarget = 1) assertEquals("↓", i.arrow) - assertEquals("3cm 내리고 측정", i.headline) + assertEquals("치골 위 1cm 에 다시 붙이고 측정", i.headline) assertTrue("왜 그 자리인지 말해야 한다", i.sub!!.contains("전부")) assertNoPositionWords(i) } @@ -107,7 +111,7 @@ class AlignInstructionTest { val i = instructionOf(step(0, searching = false, bestCm = 0), nextCm = 3, offsetCm = 1, confirmTarget = 3) assertEquals("↑", i.arrow) - assertEquals("3cm 올리고 측정", i.headline) + assertEquals("치골 위 3cm 에 다시 붙이고 측정", i.headline) assertNoPositionWords(i) } @@ -123,12 +127,12 @@ class AlignInstructionTest { // ── 확정 ──────────────────────────────────────────────────────────────── - @Test fun `확인 측정을 마치면 올리고 재지 말라고 한다`() { - // 여기가 제일 중요하다. 올린 자리를 측정하면 설계상 "미달"이 떠서 되돌아간다. + @Test fun `확인 측정을 마치면 오프셋 자리에 붙이고 재지 말라고 한다`() { + // 여기가 제일 중요하다. 그 자리를 측정하면 설계상 "미달"이 떠서 되돌아간다. val i = instructionOf(step(2, searching = false, bestCm = 2), nextCm = 2, offsetCm = 1, confirmTarget = 2, confirmDone = true) assertEquals("↑", i.arrow) - assertEquals("1cm 올리세요", i.headline) + assertEquals("치골 위 3cm 에 붙이세요", i.headline) assertTrue("측정하지 말라는 말이 빠지면 안 된다", i.sub!!.contains("측정하지 않습니다")) assertTrue("다음 단계를 말해야 멈추지 않는다", i.sub!!.contains("좌우")) assertTrue("확정은 초록이다", i.done) @@ -141,14 +145,26 @@ class AlignInstructionTest { nextCm = 2, offsetCm = 1, sweeping = true, confirmTarget = 2, confirmDone = true, needReattach = true) assertTrue(i.done) - assertEquals("1cm 올리세요", i.headline) + assertEquals("치골 위 3cm 에 붙이세요", i.headline) } @Test fun `오프셋이 바뀌면 문구도 따라간다`() { // FINAL_OFFSET_CM 을 2 로 바꾸면 화면도 2cm 이라고 말해야 한다. 박아 두면 거짓이 된다. val i = instructionOf(step(1, searching = false, bestCm = 1), nextCm = 1, offsetCm = 2, confirmTarget = 1, confirmDone = true) - assertEquals("2cm 올리세요", i.headline) + assertEquals("치골 위 3cm 에 붙이세요", i.headline) + } + + @Test fun `재부착 말고는 상대 이동을 말하지 않는다`() { + // 2026-09-29 현장: "아래로 2cm 내리세요" 가 판정 숫자와 나란히 보여 헷갈렸다. + for (sw in listOf(true, false)) for (cd in listOf(true, false)) for (t in listOf(null, 0, 2, 4)) { + val i = instructionOf(step(2, searching = false, bestCm = 0), + nextCm = 3, offsetCm = 1, sweeping = sw, confirmTarget = t, confirmDone = cd) + listOf("올리", "내리").forEach { w -> + assertFalse("\"$w\" — $i", i.headline.contains(w)) + } + if (i.headline.contains("cm")) assertTrue("치골 기준이어야 한다 — ${i.headline}", i.headline.startsWith("치골 위 ")) + } } // ── 재부착 ────────────────────────────────────────────────────────────── diff --git a/docs/CLINICAL_ALGORITHM.md b/docs/CLINICAL_ALGORITHM.md index d12383d..615e94c 100644 --- a/docs/CLINICAL_ALGORITHM.md +++ b/docs/CLINICAL_ALGORITHM.md @@ -375,19 +375,22 @@ val anchorCm: Int? get() = bestCm?.let { it + offsetCm } // offsetCm = 1 ### 3.6 실제 진행 순서 ``` -0cm 측정 → ↑ 1cm 올리고 측정 -1cm 측정 → ↑ 1cm 올리고 측정 (판정이 나빠져도 멈추지 않습니다) -2·3·4cm 측정 +치골 위 0cm 에 붙이고 측정 → ↑ 치골 위 1cm 에 붙이고 측정 + → ↑ 치골 위 2cm 에 붙이고 측정 (판정이 나빠져도 멈추지 않습니다) + → … 4cm 까지 ↓ 잰 위치 전부로 판정 → best = N ↓ -↓/↑ N cm 로 이동 → ● 여기서 한 번 더 측정 (확인 측정 = 확정 신호) +↓/↑ 치골 위 N cm 에 다시 붙이고 측정 (확인 측정 = 확정 신호 · 이미 그 자리면 "에서 한 번 더 측정") ↓ -↑ 1cm 올리세요 (초록 · 여기서는 측정하지 않음) +↑ 치골 위 N+1 cm 에 붙이세요 (초록 · 여기서는 측정하지 않음) ↓ -좌우 정렬 +좌우 정렬 (치골 위 N+1 cm 그대로) ``` +지시문의 숫자는 **치골 위 절대 위치 하나**입니다(2026-09-29). "2cm 내리고" 같은 상대 +이동은 판정 숫자와 나란히 보여 헷갈린다는 현장 의견으로 뺐고, 화살표만 방향을 거듭니다. + [여기까지만 재고 판정하기] 로 수집을 중단할 수 있습니다 — 그 시점까지의 위치로 판정합니다. #### 판정 범위가 바뀌었습니다 (2026-09-10)