factory00 — 전체 빌드 스크린샷 (최신 v0.1.297)

사이클별 자동화 캡처. publish-gallery.sh 자동 prepend (최신 위쪽). 최신 seal: 46th seal (v0.1.292) + 후속 P1.4 · 2026-05-22 KST
사이클 인덱스 (425 사이클)
v0.1.552 · v0.1.551 · v0.1.550 · v0.1.549 · v0.1.548 · v0.1.547 · v0.1.546 · v0.1.545 · v0.1.544 · v0.1.543 · v0.1.542 · v0.1.541 · v0.1.540 · v0.1.539 · v0.1.538 · v0.1.537 · v0.1.536 · v0.1.535 · v0.1.534 · v0.1.533 · v0.1.532 · v0.1.531 · v0.1.530 · v0.1.529 · v0.1.528 · v0.1.527 · v0.1.526 · v0.1.525 · v0.1.524 · v0.1.523 · v0.1.522 · v0.1.521 · v0.1.520 · v0.1.519 · v0.1.518 · v0.1.517 · v0.1.516 · v0.1.515 · v0.1.514 · v0.1.513 · v0.1.512 · v0.1.511 · v0.1.510 · v0.1.509 · v0.1.508 · v0.1.507 · v0.1.506 · v0.1.505 · v0.1.504 · v0.1.503 · v0.1.502 · v0.1.501 · v0.1.500 · v0.1.499 · v0.1.498 · v0.1.497 · v0.1.496 · v0.1.495 · v0.1.494 · v0.1.493 · v0.1.492 · v0.1.491 · v0.1.490 · v0.1.489 · v0.1.488 · v0.1.487 · v0.1.486 · v0.1.485 · v0.1.484 · v0.1.483 · v0.1.482 · v0.1.481 · v0.1.480 · v0.1.479 · v0.1.478 · v0.1.477 · v0.1.476 · v0.1.475 · v0.1.474 · v0.1.473 · v0.1.472 · v0.1.471 · v0.1.470 · v0.1.469 · v0.1.468 · v0.1.467 · v0.1.466 · v0.1.465 · v0.1.464 · v0.1.463 · v0.1.462 · v0.1.461 · v0.1.460 · v0.1.459 · v0.1.458 · v0.1.457 · v0.1.456 · v0.1.455 · v0.1.454 · v0.1.453 · v0.1.452 · v0.1.451 · v0.1.450 · v0.1.449 · v0.1.448 · v0.1.447 · v0.1.446 · v0.1.445 · v0.1.444 · v0.1.443 · v0.1.442 · v0.1.441 · v0.1.440 · v0.1.439 · v0.1.438 · v0.1.437 · v0.1.436 · v0.1.435 · v0.1.434 · v0.1.433 · v0.1.432 · v0.1.431 · v0.1.430 · v0.1.429 · v0.1.428 · v0.1.427 · v0.1.426 · v0.1.425 · v0.1.424 · v0.1.423 · v0.1.422 · v0.1.421 · v0.1.420 · v0.1.419 · v0.1.418 · v0.1.417 · v0.1.416 · v0.1.415 · v0.1.414 · v0.1.413 · v0.1.412 · v0.1.411 · v0.1.410 · v0.1.409 · v0.1.408 · v0.1.407 · v0.1.406 · v0.1.405 · v0.1.404 · v0.1.403 · v0.1.402 · v0.1.401 · v0.1.400 · v0.1.399 · v0.1.398 · v0.1.397 · v0.1.396 · v0.1.395 · v0.1.394 · v0.1.393 · v0.1.392 · v0.1.391 · v0.1.390 · v0.1.389 · v0.1.388 · v0.1.387 · v0.1.386 · v0.1.385 · v0.1.384 · v0.1.383 · v0.1.382 · v0.1.380 · v0.1.379 · v0.1.378 · v0.1.377 · v0.1.376 · v0.1.375 · v0.1.372 · v0.1.371 · v0.1.370 · v0.1.369 · v0.1.368 · v0.1.367 · v0.1.366 · v0.1.365 · v0.1.364 · v0.1.363 · v0.1.362 · v0.1.361 · v0.1.360 · v0.1.359 · v0.1.358 · v0.1.357 · v0.1.356 · v0.1.355 · v0.1.354 · v0.1.353 · v0.1.352 · v0.1.351 · v0.1.350 · v0.1.349 · v0.1.348 · v0.1.347 · v0.1.346 · v0.1.345 · v0.1.343 · v0.1.342 · v0.1.341 · v0.1.340 · v0.1.339 · v0.1.338 · v0.1.337 · v0.1.336 · v0.1.335 · v0.1.334 · v0.1.333 · v0.1.332 · v0.1.331 · v0.1.330 · v0.1.329 · v0.1.328 · v0.1.327 · v0.1.326 · v0.1.325 · v0.1.324 · v0.1.323 · v0.1.322 · v0.1.321 · v0.1.320 · v0.1.319 · v0.1.318 · v0.1.317 · v0.1.316 · v0.1.315 · v0.1.314 · v0.1.313 · v0.1.312 · v0.1.309 · v0.1.308 · v0.1.307 · v0.1.306 · v0.1.305 · v0.1.304 · v0.1.303 · v0.1.302 · v0.1.301 · v0.1.300 · v0.1.299 · v0.1.298 · v0.1.297 · v0.1.290 · v0.1.289 · v0.1.288 · v0.1.287 · v0.1.286 · v0.1.285 · v0.1.284 · v0.1.283 · v0.1.282 · v0.1.281 · v0.1.280 · v0.1.279 · v0.1.278 · v0.1.277 · v0.1.276 · v0.1.274 · v0.1.273 · v0.1.272 · v0.1.271 · v0.1.270 · v0.1.269 · v0.1.268 · v0.1.267 · v0.1.266 · v0.1.265 · v0.1.264 · v0.1.263 · v0.1.262 · v0.1.261 · v0.1.260 · v0.1.259 · v0.1.258 · v0.1.257 · v0.1.256 · v0.1.255 · v0.1.254 · v0.1.253 · v0.1.252 · v0.1.251 · v0.1.250 · v0.1.249 · v0.1.248 · v0.1.247 · v0.1.246 · v0.1.245 · v0.1.244 · v0.1.243 · v0.1.242 · v0.1.241 · v0.1.240 · v0.1.239 · v0.1.238 · v0.1.237 · v0.1.236 · v0.1.235 · v0.1.234 · v0.1.233 · v0.1.232 · v0.1.231 · v0.1.230 · v0.1.229 · v0.1.228 · v0.1.227 · v0.1.226 · v0.1.225 · v0.1.224 · v0.1.223 · v0.1.222 · v0.1.221 · v0.1.220 · v0.1.219 · v0.1.218 · v0.1.217 · v0.1.216 · v0.1.215 · v0.1.214 · v0.1.213 · v0.1.212 · v0.1.211 · v0.1.209 · v0.1.207 · v0.1.206 · v0.1.205 · v0.1.204 · v0.1.203 · v0.1.202 · v0.1.201 · v0.1.200 · v0.1.199 · v0.1.198 · v0.1.197 · v0.1.196 · v0.1.195 · v0.1.194 · v0.1.193 · v0.1.192 · v0.1.191 · v0.1.190 · v0.1.189 · v0.1.188 · v0.1.187 · v0.1.186 · v0.1.185 · v0.1.184 · v0.1.183 · v0.1.182 · v0.1.181 · v0.1.180 · v0.1.179 · v0.1.178 · v0.1.177 · v0.1.176 · v0.1.175 · v0.1.174 · v0.1.173 · v0.1.172 · v0.1.171 · v0.1.170 · v0.1.169 · v0.1.166 · v0.1.165 · v0.1.164 · v0.1.163 · v0.1.162 · v0.1.161 · v0.1.160 · v0.1.159 · v0.1.158 · v0.1.157 · v0.1.155 · v0.1.154 · v0.1.153 · v0.1.152 · v0.1.151 · v0.1.150 · v0.1.149 · v0.1.148 · v0.1.147 · v0.1.146 · v0.1.145 · v0.1.144 · v0.1.143 · v0.1.142 · v0.1.141 · v0.1.140 · v0.1.139 · v0.1.138 · v0.1.137 · v0.1.136 · v0.1.135 · v0.1.134 · v0.1.133 · v0.1.132 · v0.1.131 · v0.1.130 · v0.1.129 · v0.1.128 · v0.1.127 · v0.1.126 · v0.1.125 · v0.1.124 · v0.1.123 · v0.1.122 · v0.1.120 · v0.1.119 · v0.1.118 · v0.1.117 · v0.1.114 · v0.1.113 · v0.1.112 · v0.1.111 · v0.1.110 · v0.1.109 · v0.1.108 · v0.1.107

v0.1.552 — v0.1.552 — QA-130 카메라 입력 클러스터 2축 REAL FIX (PM r012: 화이트리스트 폐기 + ALT false-trigger)

v0.1.552 v0.1.552 — QA-130 카메라 입력 클러스터 2축 REAL FIX (PM r012: 화이트리스트 폐기 + ALT false-trigger) zip release notes GitHub
PM v0.1.551 무효 (2축 root cause 확정, report-0051)
축1 focus 고착: 스모킹건 focused='cmd-open' Blur+flag IsAnyUIFocused=True. cmd-open(불러오기 버튼)이 IsLnbElementFocused 화이트리스트(_lnbCmds Contains)에 누락 — v0.1.551 _lnbTabs 만 추가→_lnbCmds 누락 재발. critic 자체검증과 PM 실측 불일치.
축2 ALT false-trigger: WASD 가 LeftAlt down false-set ([alt] downTime Ldn=True 6건), v0.1.551 미touch.
• JP 결정: QA-123/134/136/081/087 → QA-130 "카메라 입력 클러스터" 통합 종결(git rm).
fix (PM/JP 승인 방향, 2축 동시)
축1: IsLnbElementFocused(element 화이트리스트) 폐기 — 누락 element 마다 재발하는 구조 취약성 제거. "카메라 의도 플래그 우선" 단순화: _cameraFocusRestorePending true + 메뉴 닫힘 + 텍스트입력 아님 → 카메라 통과(어느 element focus 든).
축2: Alt 감지 시 WASD/QE(카메라 키) 동시 누름이면 LeftAlt false-trigger(Unity 폴링 오인식) 무시.
[alt]/focusedElement 진단 로그 유지 (PM regression-diagnosis §0순위).
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — IsAnyUIFocused 플래그 우선 판정 + IsLnbElementFocused 제거 + Alt 감지 camKeyHeldForAlt 가드
검증
• 컴파일: Unity batch
• 2축 (불러오기 후 카메라 복귀 + WASD 시 ALT 미발생 + ESC 후 차단): 마우스+키보드 조합 → PM Stage 2 (3회째 — 실측이 진실, 자동화/critic 한계 인정). 진단 로그 focusedElement name 으로 고착 element 확인.

v0.1.551 — v0.1.551 — QA-130/136 통합 카메라 먹통 root cause REAL FIX (focus 고착 플래그 우회)

v0.1.551 v0.1.551 — QA-130/136 통합 카메라 먹통 root cause REAL FIX (focus 고착 플래그 우회) zip release notes GitHub
PM v0.1.550 QC 무효 → 재fix
• 스모킹건(PM Player.log L332): _focusDummy.Focus()IsAnyUIFocused()=True → Focus() 가 focus 를 실제로 안 옮김. v0.1.550 내 fix(_focusDummy.Focus() 추가) 무효.
• QA-130(WASD 시 메뉴바 ALT outline)+QA-136(불러오기 후 카메라 먹통) 동일 root cause = 메뉴바 헤더(_lnbTabs)/명령 버튼(_lnbCmds) focus 고착.
fix (판정 우회 — Focus/Blur 무효 무관)
_cameraFocusRestorePending 플래그: 메뉴 명령 클릭/viewport 클릭/불러오기(카메라 복귀 의도) set, Tab 순회/메뉴 열림(ShowLnbDropdown) clear.
IsAnyUIFocused(): 플래그 true + 메뉴 닫힘(_lnbActiveIdx<0) + lnb element focus = 카메라 통과. Tab 헤더 focus 는 플래그 false → 차단 유지(focus-key-isolation 양립).
• viewport-focus-anchor 제외 추가. Blur 는 best-effort outline clear.
critic 2-pass
• 1차 FAIL: 치명(Tab 순회 헤더 focus 도 카메라 통과 → 룰 위반) → 플래그 도입.
• 2차 CONDITIONAL: 중대1(ESC stale)→ShowLnbDropdown clear / 중대3(IsLnbElementFocused _lnbTabs Contains 누락)→추가. 중대2(외부클릭 비일관, 실질 재현 낮음)+중대4(OpenTwn 로그 PM QC 요청 unconditional)는 사유 보류.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — IsAnyUIFocused/IsLnbElementFocused + HideLnbDropdown/OpenTwn 플래그 set + Tab/ShowLnbDropdown clear + 진단 로그(focusedElement name, PM report-0050)
검증
• 컴파일: Unity batch
• 카메라 먹통/ALT outline: 마우스+키보드 조합 → PM Stage 2 의무 (자동화 한계). 진단 로그 focusedElement name 으로 고착 element 확인 가능.

v0.1.550 — v0.1.550 — QA-138/136 카메라 먹통 root cause fix (메뉴 명령 후 focus 복원 일반화)

v0.1.550 v0.1.550 — QA-138/136 카메라 먹통 root cause fix (메뉴 명령 후 focus 복원 일반화) zip release notes GitHub
핵심 변경
HideLnbDropdown(bool restoreCameraFocus) 파라미터 추가 — 메뉴 명령/viewport 클릭으로 닫을 때 _focusDummy 로 focus 복원
• root cause: 메뉴 명령 버튼(focusable=true, L1830 Tab 순회용)이 클릭 시 focus 고착 → IsAnyUIFocused()=true 영구 → 카메라 입력(WASD/휠/Space/C) 전면 차단
• QA-136(불러오기)은 OpenTwn(L3279) 복원으로 가려졌으나, 시점전환·기타 모든 메뉴 명령 경로는 복원 누락 → 반복 재발. 본 fix로 메뉴 경로 일반화
• ESC 경로는 기본값 false 유지 → 메뉴 헤더 focus 복귀(focus-tab-navigation) 충돌 회피
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — HideLnbDropdown 시그니처 + L1823(메뉴 명령 클릭 true) + L4746(viewport 클릭 true)
검증
• 컴파일: Unity batch 빌드 (csc C#9 검증 불가 — Unity 유일 컴파일 검증)
• cascade 점검: HideLnbDropdown 호출처 7곳 — L1867(ESC 헤더복귀)/L1877(초기)/L1888(외부클릭)/L1911(ESC) 모두 false 적절, 회귀 0
• 카메라 먹통 재현: 뷰메뉴 마우스 클릭 + WASD = 마우스+키보드 조합 → Stage 2 사용자 PC 검증 의무 (자동화 한계)

v0.1.549 — v0.1.549 — QA-116 반복 STEP import 부모 Part id 충돌 fix (import 세션 unique prefix)

v0.1.549 v0.1.549 — QA-116 반복 STEP import 부모 Part id 충돌 fix (import 세션 unique prefix) zip release notes GitHub
협업자 QA-116 (STEP import 반복 시 부모 중복 등록 + 부모 선택 시 동일 도면 전체 기즈모 동조 — v0.1.389 발견, 진짜 미처리)
• root cause(코드 확정): GltfPartImporter.MakeId 는 계층 경로 name#siblingIndex 로 id 생성 — 단일 import 내에서만 unique. ImportGlbAsync 가 BuildParts(root.transform) 를 idPrefix="" 기본값으로 호출 → 같은 도면 재import 시 root=new GameObject(fileName)(동일 fileName) → 부모 Part id 충돌. 증상 1=Parts.AddRange 중복 등록 / 증상 2=같은 parentId 로 자식 묶여 부모 선택 시 전체 동조.
• fix: ImportGlbAsync 에 idPrefix 파라미터 추가(L162) + BuildParts 전파(L195). cmdImportStep(L1972)이 PlayerPrefs 영속 카운터 factory00.import_seq 로 import 세션마다 unique prefix(imp{seq}) 전달 → 같은 도면 재import 도 id 분리(앱 재시작에도 단조 증가). OpenTwnPath 재import(L3211)는 직후 payload id 로 교체(L3216)라 idPrefix 무관 — 영향 0.
영향 파일
Assets/Scripts/Importers/StepImportService.cs — ImportGlbAsync idPrefix 파라미터 + BuildParts 전파
Assets/Scripts/Game/Factory00Bootstrap.cs — cmdImportStep PlayerPrefs 카운터 unique prefix
검증
• 정적: BuildParts 호출처 cascade 점검 — L312 부팅 번들 import 는 1회(반복 없음, idPrefix "" 안전) / L195 fix 적용 / L3211 payload 교체로 무관. prefix 다르면 id 분리(L107-108 명확).
• 빌드: 컴파일 검증.
• Stage 2 PM QC: 같은 STEP 도면 2회 import → 부모 중복 없음 + 각 부모 선택 시 해당 도면만 이동(전체 동조 소멸). 반복 import 마우스 트리거(파일 피커) → autoQA 제거로 자체 헤드리스 불가.

v0.1.548 — v0.1.548 — QA-136 불러오기 후 카메라 전면 먹통 fix (focus 고착 해제)

v0.1.548 v0.1.548 — QA-136 불러오기 후 카메라 전면 먹통 fix (focus 고착 해제) zip release notes GitHub
협업자 QA-136 (프로젝트 불러온 후 카메라 조작 전면 먹통 — v0.1.492 QC 발견, 진짜 미처리)
• root cause(코드 확정): OpenTwnPath 완료 시 ListView Rebuild / payload 적용 중 UI element(리스트 항목 등)가 focus 잡으면 IsAnyUIFocused()=true 고착. camCtrl.IsTextInputFocused(L439)=IsAnyUIFocused 가드로 WASD/C/Space/휠/orbit 카메라 입력 전면 차단(휠 포함 = PM 추정 확정). L529 _focusDummy startup 고착 동종 이력.
• fix(방어적): OpenTwnPath 성공 완료 시 _focusDummy.Focus() — IsAnyUIFocused()=false(L531 제외) + polling 재 focus 대상과 일관. focus 고착 element 무관 해제. 주의: _viewportFocusAnchor 는 IsAnyUIFocused 제외 목록(L518~535)에 없어 Focus 시 true → 카메라 차단 유지 = 함정. _focusDummy 가 정답.
• 검증 한계: OpenTwnPath 는 파일 피커 / Recent 버튼 마우스 트리거(autoQA 인-프로세스 제거됨, qa-real-input-only) → 불러오기 후 카메라 복귀는 Stage 2 PM QC. Debug.Log [QA-136] IsAnyUIFocused=false 로 Player.log 검증 가능.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — OpenTwnPath 완료 시 _focusDummy.Focus() + 진단 로그(+8라인)
검증
• 정적: root cause L439 카메라 가드 + L531 IsAnyUIFocused 제외 확정. _focusDummy.Focus() 다음 IsAnyUIFocused=false 다음 카메라 복귀 인과 명확.
• 빌드: 컴파일 검증 + 캡처(앱 정상 부팅 회귀 0).
• Stage 2: PM 불러오기 후 WASD/휠 카메라 입력 복귀 확인 + Player.log [QA-136] IsAnyUIFocused=false.

v0.1.547 — v0.1.547 — QA-146 cascade: 셰이더 swap 경로 _Cull 누락 일괄 fix + ApplyDoubleSided SSOT

v0.1.547 v0.1.547 — QA-146 cascade: 셰이더 swap 경로 _Cull 누락 일괄 fix + ApplyDoubleSided SSOT zip release notes GitHub
QA-146 cascade 예방 (전방향 양면 정책 SSOT화)
• v0.1.543 QA-146 은 Factory00MaterialGenerator.CreateBaseUnlit 만 _Cull=0(양면). cascade 점검(cycle-critic-review) 결과 SwapToUnlitShader / SwapToLitShader 의 케이스 A(broken→runtime 머티리얼 생성) + 케이스 B(셰이더 swap) 4 경로 모두 _Cull 누락 → Lit↔Unlit 토글 / broken 머티리얼 fallback 시 backface 컬링으로 뒤/왼/아래 면 누락 잔존.
• SSOT 모듈화: Factory00MaterialGenerator.ApplyDoubleSided(mat) static 헬퍼 신설. CreateBaseUnlit + SwapToUnlitShader(A/B) + SwapToLitShader(A/B) = 5 경로 공통 호출. 전방향 양면 정책 단일 지점(향후 누락 차단, "문제 발생 코드만 분리" 원칙).
영향 파일
Assets/Scripts/Game/Factory00MaterialGenerator.cs — ApplyDoubleSided static SSOT + CreateBaseUnlit 호출 교체
Assets/Scripts/Game/Factory00Bootstrap.cs — SwapToUnlitShader / SwapToLitShader 케이스 A/B 4곳 ApplyDoubleSided 호출
검증
• 정적: _Cull set 경로 = ApplyDoubleSided 단일(정의 1 + 호출 5). 임포트 머티리얼 모든 경로(MaterialGenerator / Unlit swap / Lit swap) 양면 일관. Sprites/Default 오버레이는 backface 무관(제외).
• 동적: Lit↔Unlit 토글 후 뒤/왼/아래 뷰 면 누락 0 = Stage 2(뷰 메뉴 마우스). 정상 Unlit 임포트는 v0.1.543 헤드리스 검증 완료(회귀 0).

v0.1.546 — v0.1.546 — QA-151 cascade: IsPointerOverUI geometry 폴백 5개 floating 패널 일반화

v0.1.546 v0.1.546 — QA-151 cascade: IsPointerOverUI geometry 폴백 5개 floating 패널 일반화 zip release notes GitHub
QA-151 cascade 예방 (PLC 전용 → 5 floating 패널)
• v0.1.545 는 PLC 매핑 패널만 worldBound geometry 폴백. cascade 점검(cycle-critic-review) 결과 나머지 4개 floating 패널(Modbus / SignalSim / ModbusTcp / Mitsubishi)도 동일 IResizableWindow + Root + IsVisible 구조 → 같은 panel.Pick 누락 노출(드래그는 PLC만이나 click / 카메라 회전 오인 공통).
• 일반화: IsPointerOverUI 의 PLC 하드코딩 → FloatingSubWindows() 공통 순회. 신규 floating 패널은 본 메서드 1줄 등록으로 자동 안전망(모듈화 단일 지점, "문제 발생 코드만 분리" 원칙).
• 회귀 0: 기존 Pick path 보존 + 각 패널 IsVisible 가드(닫힘 무영향). 4개 패널 보고 0이나 동일 구조 예방.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — IsPointerOverUI 순회 교체 + FloatingSubWindows() 헬퍼 신규(+12라인)
검증
• 정적: 5 패널 모두 Root(VisualElement) + IsVisible(bool) 노출 확인(grep). ValueTuple yield, 핫패스 미미(대부분 IsVisible=false 즉시 skip).
• 동적: 마우스 box-select / click 동작은 Stage 2 협업자 QC.

v0.1.545 — v0.1.545 — QA-151 box-select 누수 geometry 안전망 (IsPointerOverUI Pick 폴백)

v0.1.545 v0.1.545 — QA-151 box-select 누수 geometry 안전망 (IsPointerOverUI Pick 폴백) zip release notes GitHub
협업자 QA-151 (S0048 PLC 매핑 에디터 — 포트 드래그가 3D 씬 box-select 유발)
• root cause(정적 분석 확정 범위): box-select 가드(Bootstrap L4766)는 !overUIAtDown (= IsPointerOverUI(_lmbDownPos)) 로 패널 위 드래그를 차단하나, IsPointerOverUI 의 panel.Pick 이 PLC 매핑 패널 일부 영역을 누락 → overUIAtDown=false → box-select 시작. overUIAtDown 은 _lmbDownPos 고정 평가라 프레임 dispatch 순서는 root cause 아님 (Pick 누락 단일 원인). panel.Pick 누락 = QA-097 LNB dropdown 동종 이력(L4716, 6차 fix).
• fix(geometry 안전망): IsPointerOverUI 에 Pick 폴백 추가 — 가시 PLC 패널(_plcMappingPanel.IsVisible)의 _root.worldBound.Contains(panelPos) 시 UI 로 판정. Pick 누락/타이밍 무관, 패널 닫힘 시 무영향(IsVisible 가드). box-select / click / 카메라 회전 모든 호출처 동시 보강.
• PortDragController 의 _plcMappingDragActive(PointerDown 즉시 set) 유지 — 본 fix 는 그 외 영역(헤더/빈 영역/Pick 누락 행) 드래그 시작까지 포괄하는 상위 안전망.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — IsPointerOverUI geometry 폴백 +6라인
검증
• 정적: Pick 폴백 OR 추가, 기존 Pick path 보존 → 회귀 0. _plcMappingPanel.Root(L47) / IsVisible(L46) 기존 노출 멤버 소비 (PLC 패널 측 변경 0).
• 동적: 패널 열기가 C5 버튼 마우스 → 포트 드래그 box-select 누수 재현은 Stage 2(협업자 QC). geometry 안전망이라 root cause 가 Pick 누락이든 타이밍이든 포괄.

v0.1.544 — v0.1.544 — QA-150 PLC 매핑 에디터 닫기 수단 (X버튼 + ESC)

v0.1.544 v0.1.544 — QA-150 PLC 매핑 에디터 닫기 수단 (X버튼 + ESC) zip release notes GitHub
협업자 QA-150 (S0048 PLC 매핑 에디터 닫기 수단 부재 — 사용자 갇힘)
• root cause(코드 검증, PM 진단 A 확정): PlcAddressMappingPanel 은 독립 오버레이(IResizableWindow + Attach)라 기존 _subWindowOverlay backdrop / CloseSubWindow / ESC cascade 가 도달 안 함. C5 버튼(addr-mapping-open)이 open-only(토글 분기 없음) → 닫기 수단 전무. 다른 4 서브윈도우는 리본 재클릭 토글 있어 갇힘 아님 → PLC만 대상(cascade 검토 확정).
• fix(자율분): (1) titleBar 에 X 닫기 버튼(Hide 연결, [B] 드래그는 WireMove 의 evt.target is Button 가드로 공존) (2) ESC cascade 에 PLC 패널 분기 편입(서브윈도우 직후, 상호배타라 순서 무충돌).
• 씬클릭 backdrop = 전체화면 backdrop element 신규 + z-order 재배치 구조 변경이라 Stage 2 분리(마우스).
영향 파일
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (X 닫기 버튼)
Assets/Scripts/Game/Factory00Bootstrap.cs (ESC cascade PLC 분기 + 주석)
검증
• 컴파일 + 코드 ferry 명확. 패널 열기가 C5 버튼 마우스라 X버튼 시각·ESC 동작은 Stage 2 PC(열기 후 ESC/X 클릭).

v0.1.543 — v0.1.543 — QA-146 backface culling 면 누락 fix (전방향 양면 렌더)

v0.1.543 v0.1.543 — QA-146 backface culling 면 누락 fix (전방향 양면 렌더) zip release notes GitHub
협업자 QA-146 (뒤/왼/아래 뷰 전환 시 면 누락 — backface culling)
• root cause: Factory00MaterialGenerator.CreateBaseUnlit 이 single-sided URP/Unlit 머티리얼 생성 + doubleSided=true glb 만 _Cull=0 적용. 산업 STEP/glTF 메시 대부분 doubleSided=false → 카메라가 backface 보는 각도(뒤/왼/아래)에서 면 컬링 누락. PM 진단 (A) backface culling 일치.
• fix: CreateBaseUnlit(default + glb 단일 생성 지점)에서 모든 임포트 머티리얼 무조건 _Cull=0(CullMode.Off). CAD 트윈은 전방향 관찰이 기본 use-case. 기존 doubleSided 분기 제거(중복).
• spec-implementation-judgment: PM 권장(셰이더 Cull Off OR normal 양면화) 중 머티리얼 _Cull=0 이 코드 최소·검증된 path(normal 재계산보다 안전).
영향 파일
• 수정: Assets/Scripts/Game/Factory00MaterialGenerator.cs (CreateBaseUnlit _Cull=0 무조건 + doubleSided 분기 제거)
검증
• 컴파일 + 뒤/왼/아래 뷰 캡처 + Read tool 픽셀 대조(면 누락 소멸 확인). 마우스 무관 헤드리스 full 검증.

v0.1.542 — v0.1.542 — QA-086 [B] critic fix (titleBar 버튼 가드 + BuildContent Clear 시한폭탄 제거)

v0.1.542 v0.1.542 — QA-086 [B] critic fix (titleBar 버튼 가드 + BuildContent Clear 시한폭탄 제거) zip release notes GitHub
critic 코드리뷰 fix (v0.1.541 CONDITIONAL → 처리)
• 치명#2 (titleBar 위 버튼 클릭 시 드래그 발화): ResizableWindowController.WireMove 에 evt.target is Button 가드 — Refresh/모드 버튼 클릭은 창 이동 안 함. title Label 등 비-Button 영역은 드래그 허용.
• 치명#1 (ModbusTcp/Mitsubishi BuildContent _root.Clear() 시한폭탄): 제거. Build 1회 + 빈 _root 라 잉여 + 미래 재호출 시 리사이즈 핸들 삭제 위험 차단.
• 중대#1·2 (3패널 onDragStateChanged 누락): false-positive 판정 — Bootstrap box-select 가 overUIAtDown(IsPointerOverUI(_lmbDownPos))으로 titleBar/핸들(UI) 위 드래그를 이미 차단. PLC 의 콜백은 PortDragController(포트 후보 드래그)용이지 titleBar 드래그가 아님. 미부착 안전.
영향 파일 (3)
Assets/Scripts/UI/ResizableWindowController.cs (WireMove 버튼 가드)
Assets/Scripts/Communication/Modbus/ModbusTcpInspectorPanel.cs (Clear 제거)
Assets/Scripts/Communication/Mitsubishi/MitsubishiPlcDriverPanel.cs (Clear 제거)
검증
• 컴파일 + Stage 2: 5개 서브윈도우 드래그/리사이즈/복원 + 타이틀바 버튼 클릭 시 창 미이동. (마우스 = Stage 2 PC)

v0.1.541 — v0.1.541 — QA-086 [B] 서브윈도우 이동·리사이즈 5패널 완성 (사이클2: 나머지 4패널)

v0.1.541 v0.1.541 — QA-086 [B] 서브윈도우 이동·리사이즈 5패널 완성 (사이클2: 나머지 4패널) zip release notes GitHub
협업자 QA-086 [B] / spec S0055 P2 (서브윈도우 이동·리사이즈) — 5패널 부착 완성
• 사이클1(v0.1.540) ModbusAddressMapping 패턴을 나머지 4패널에 적용:
◦ PlcAddressMapping (left, Render Clear 있음): 2층 분리(_contentRoot). OnDragStateChanged 재사용. ConfirmModal 독립 유지.
◦ SignalSimulator (right, Render Clear 있음): 2층 분리 + right 환산. SignalControlPopup 독립.
◦ ModbusTcpInspector (right, Clear 없음): titleBar Row 신설 + right 환산. 2층 불요(BuildContent 1회).
◦ MitsubishiPlcDriver (right, Clear 없음): 동일.
• 5패널 전부 IResizableWindow + Attach (드래그 이동 + 8방향 리사이즈 + 최소크기 + PlayerPrefs 영속).
• right 기준 3패널 DefaultPosition.x=1524 (1920-380-16), ClampPos 작은 화면 자동 조정.
• [A] z-order SendToBack 유지, BringToFront 0건.
영향 파일 (4)
Assets/Scripts/Plc/PlcAddressMappingPanel.cs
Assets/Scripts/Communication/Modbus/SignalSimulatorPanel.cs
Assets/Scripts/Communication/Modbus/ModbusTcpInspectorPanel.cs
Assets/Scripts/Communication/Mitsubishi/MitsubishiPlcDriverPanel.cs
검증
• 컴파일 + critic + Stage 2: 5개 서브윈도우 타이틀바 드래그 이동 / 8방향 리사이즈 / 최소크기 / PlayerPrefs 위치·크기 복원. (마우스 = 헤드리스 자동검증 불가, Stage 2 PC)

v0.1.540 — v0.1.540 — QA-086 [B] 서브윈도우 이동·리사이즈 부착 (사이클1: Modbus 매핑 패널)

v0.1.540 v0.1.540 — QA-086 [B] 서브윈도우 이동·리사이즈 부착 (사이클1: Modbus 매핑 패널) zip release notes GitHub
협업자 QA-086 [B] / spec S0055 P2 (서브윈도우 이동·리사이즈)
• 인프라(C1 SubWindowLayout/IResizableWindow + C2 SubWindowLayoutStore PlayerPrefs + C3 ResizableWindowController 드래그/8방향리사이즈/clamp + EventBus)는 이전 사이클에 완성·critic 통과. 본 사이클 = P2 패널 부착 시작.
• 사이클1: ModbusAddressMappingPanel 부착 (5개 서브윈도우 중 _root.Clear() 리스크 최대 → 옵션 A 패턴 먼저 확립).
• 옵션 A (2층 분리): _root(Clear 안 함, titleBar + contentRoot + 리사이즈 핸들 8개) / _contentRoot(Render 가 이것만 Clear). 기존 Render 의 _root.Clear() 가 리사이즈 핸들을 삭제하던 회귀 차단.
• IResizableWindow 구현(WindowId / MinSize 360x220 / MaxSize 무제한 / Default 16,110,520,600) + Build 에서 Attach. 타이틀바 드래그 이동 + 8방향 리사이즈 + 최소크기 + PlayerPrefs 위치/크기 영속 + 복원.
• [A] z-order SendToBack 유지 (BringToFront 미추가 → 계층 불변).
영향 파일
• 수정: Assets/Scripts/Communication/Modbus/ModbusAddressMappingPanel.cs (IResizableWindow + 2층 분리 + Attach)
• 기존 인프라(무변경): Assets/Scripts/UI/{SubWindowLayout,SubWindowLayoutStore,ResizableWindowController}.cs, Events/SubWindowEvents.cs
검증
• 컴파일 + Stage 2: Modbus 매핑 패널 타이틀바 드래그 이동 / 8방향 테두리 리사이즈 / 최소크기 / 닫았다 열면 위치 복원. (마우스 드래그 = 헤드리스 자동검증 불가, Stage 2 PC 의무)
• 나머지 4개 패널(PLC매핑/시그널시뮬/ModbusTCP/미쓰비시) 부착은 사이클 2(critic 의무).

v0.1.539 — v0.1.539 — QA-086 [A] 서브윈도우 z-order 계층 확립 (5개 floating 패널)

v0.1.539 v0.1.539 — QA-086 [A] 서브윈도우 z-order 계층 확립 (5개 floating 패널) zip release notes GitHub
협업자 QA-086 [A] (서브윈도우가 SNB 뒤로 숨음 — z-order war)
• root cause: 서브윈도우(매핑/시뮬/인스펙터)가 BringToFront(PLC) 또는 무처리인데, 메뉴 드롭다운이 hud-root(SNB+메뉴바) BringToFront(QA-079) → 메뉴 한 번 누르면 서브윈도우가 SNB 뒤로 묻힘. 과거 v0.1.404/504 fix는 무관한 전체화면 모달(_subWindowOverlay)만 건드려 실제 매핑 서브윈도우 미적중.
• spec WHAT(handshake QA-086 [A]): 씬 < 서브윈도우 < SNB < 메뉴바 계층. SNB가 서브윈도우를 가리되, SNB 접힘 시 자유 표시. 메뉴바 항상 최상위(QA-079).
• fix: 5개 floating 서브윈도우(PLC매핑/Modbus매핑/시그널시뮬/ModbusTCP인스펙터/미쓰비시인스펙터) Show·Toggle에서 _root.SendToBack() — 표시 시 항상 chrome(hud-root) 아래로 고정. hud-root BringToFront(메뉴바 최상위)·모달 BringToFront(최상위)는 불변. z-order war 제거.
• 각 패널이 자기 Show에서 z-order 책임(OOP 격리). spec [B] 이동·리사이즈는 다음 큐.
영향 파일 (5)
Assets/Scripts/Plc/PlcAddressMappingPanel.cs
Assets/Scripts/Communication/Modbus/ModbusAddressMappingPanel.cs
Assets/Scripts/Communication/Modbus/SignalSimulatorPanel.cs
Assets/Scripts/Communication/Modbus/ModbusTcpInspectorPanel.cs
Assets/Scripts/Communication/Mitsubishi/MitsubishiPlcDriverPanel.cs
검증
• 컴파일 + critic z-order 회귀 검토 + Stage 2: 서브윈도우 열고 메뉴 클릭 → 서브윈도우가 SNB 아래 유지(가려지되 메뉴바 클릭 가능), SNB 접으면 표시

v0.1.538 — v0.1.538 — QA-106 포커스 검출 견고화 (inner __selectable TextElement 포괄)

v0.1.538 v0.1.538 — QA-106 포커스 검출 견고화 (inner __selectable TextElement 포괄) zip release notes GitHub
협업자 QA-106 후속 (Inspector 값 입력 중 필드 destroy 방지 견고화)
• 배경: QA-106 자체는 v0.1.501 REAL FIX 완료 (편집 중 RenderInspector skip). 본 사이클은 잔존 edge case 견고화.
• root cause(잔존): Unity6 UI Toolkit은 TextField focus 시 focusedElement가 TextField가 아니라 내부 __selectable TextElement (v0.1.468 학습). 포커스 검출이 타입 체크 (focused is TextField) 만 하면 inner TextElement를 놓쳐 값-변경 re-render가 편집 중 통과 가능.
• fix: IsInspectorTextInputFocused / IsAnyTextFieldFocused 두 헬퍼에 조상 검색 (GetFirstAncestorOfType) 추가 — inner TextElement까지 텍스트 입력으로 인식.
• 효과: Inspector 값 편집 중 카메라 단일키 (WASD) 발화 차단 + RenderInspector skip 가드 정확도 상승.
영향 파일
• 수정: Assets/Scripts/Game/Factory00Bootstrap.cs (IsInspectorTextInputFocused / IsAnyTextFieldFocused — ancestry 포괄)
검증
• 컴파일 (GetFirstAncestorOfType = UI Toolkit 표준 API) + Stage 2: Inspector float 필드 편집 중 WASD 무발화 + 값 입력 정상 반영

v0.1.537 — v0.1.537 — QA-129 Fix B 서보축 구동 범위 씬 비주얼라이저

v0.1.537 v0.1.537 — QA-129 Fix B 서보축 구동 범위 씬 비주얼라이저 zip release notes GitHub
협업자 QA-129 Fix B (구동 범위 씬 미표시 — 직진 실린더는 정상)
• root cause(에이전트): ServoAxisVisualizer 클래스 자체가 없음. Pneumatic은 PneumaticStrokeBarVisualizer가 매 프레임 LineRenderer 갱신 → "직진 실린더 정상"의 정체
• fix: 신규 ServoAxisVisualizer (PneumaticStrokeBarVisualizer 패턴 미러) — RLS~FLS 구동 범위 바(회색) + 현재 무버 마커(파랑/이동중 녹색, CurrentVelocity 기준). m→mm ×1000(unit-mm-conversion). useWorldSpace로 owner 위치 매 프레임 추적, owner 선택 시만 표시.
ActuatorDriver: _servoVisualizers dict + RegisterActuator 서보 분기(Driver 자식 ghost 회피) + Unregister/UnregisterAll 정리 (Pneumatic 패턴 미러, Material/GameObject leak 0)
QA-129 완결 (Fix A v536 + Fix B v537)
• Fix A: 모니터링 실시간 갱신(schedule.Every(100)) / Fix B: 구동 범위 비주얼라이저. enum 통일만 별도(동작 무관, S0047)
영향 파일
• 신규: Assets/Scripts/Actuators/ServoAxisVisualizer.cs
• 수정: Assets/Scripts/Actuators/ActuatorDriver.cs (서보 visualizer 등록/정리)
검증
• 컴파일(PneumaticStrokeBarVisualizer 패턴 미러, API 정합) + Stage 2: 서보 부착 부품 선택 → 씬에 RLS~FLS 막대 + 무버 표시 / 명령 시 무버 이동

v0.1.536 — v0.1.536 — QA-129 서보축 모니터링 실시간 갱신 fix (Fix A)

v0.1.536 v0.1.536 — QA-129 서보축 모니터링 실시간 갱신 fix (Fix A) zip release notes GitHub
협업자 QA-129 (서보 모니터링 Stopped/0 고정·간헐) — 에이전트 심층 조사
• PM 1순위(Inspector 갱신 사이클 결함) 정확, dev 가설 1(PLC path 끊김)·3(enum 미통일) 반증(코드 검증):
◦ 명령 경로 3개 모두 살아있음(수동버튼/PLC Coil/sim-stop) → 서보는 실제 구동, 표시만 stale
◦ ActuatorType enum은 직렬화/표시 전용 — 드라이브는 ActuatorState로만 분기, 동작 무관
진짜 root cause(Fix A): 모니터링 행이 정적 Label(빌드 스냅샷) + RenderInspector 0.25s 주기가 5초 grace(QA-106 입력필드 보호)로 skip → 값 얼어붙음
fix: SensorReadonlyRowRef(value Label 참조 반환) + card.schedule.Execute(...).Every(100)로 상태/현재위치/현재속도 텍스트만 매 100ms 갱신. 카드 panel 떠나면 자동 중단, 입력필드 destroy 부작용 0. PLC 비의존(수동/데모 구동)
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs (SensorReadonlyRowRef 헬퍼 + RenderServoAxisCard 모니터링 schedule 갱신)
잔존 (QA-129 Fix B — 다음 사이클)
• 구동 범위 씬 미표시 = ServoAxisVisualizer 부재(Pneumatic은 PneumaticStrokeBarVisualizer 있음). 신규 visualizer + RegisterActuator 서보 분기 = 다음 빌드. enum 통일은 별도(동작 무관, S0047 마이그레이션 동반)
검증
• 컴파일(.Every API 기존 L116/90/57 정합) + Stage 2: 서보 카드 열고 명령 → 값 실시간 변화 확인

v0.1.535 — v0.1.535 — QA-119 Save/Load 삭제-재오픈 미복원 fix (soft-delete 복원)

v0.1.535 v0.1.535 — QA-119 Save/Load 삭제-재오픈 미복원 fix (soft-delete 복원) zip release notes GitHub
협업자 QA-119 (예시2: 삭제 후 재오픈 미복원) — spec-implementation-judgment
• PM 가설(A: Open이 GameObject.Instantiate 누락)은 현상은 맞으나 구조상 불가능: factory00 import-only = mesh 미직렬화 → 단품 Instantiate 불가(mesh 출처 GLB/STEP 재임포트뿐)
진짜 root cause(에이전트 심층 조사): 삭제(DeleteCommand)=SetActive(false)+Parts 리스트 유지(soft delete) → .twn에 파트 영속 → 재오픈 시 byId 매칭+속성 덮어쓰기는 되나 비활성 GameObject를 SetActive(true)로 안 되살림. A는 "재생성"이 아니라 "복원"이 정답.
fix: ApplyTwnPayloadCore 매칭부 — payload에 있는 파트가 비활성이면 SetActive(true)(soft-delete 복원). 숨김(visibility)은 Renderer.enabled 도메인이라 SetActive 무관(parts-visibility 블록 별도) → 숨긴 파트는 활성+Renderer off 유지
• 회귀 최소 옵션(에이전트 4옵션 비교): 재임포트/clear 무변경, 정상 Open(예시3 GLB fallback)·Duplicate 파트 무손상
PM 확인 필요 (spec 의도)
• 삭제 영속 정책: 현재 삭제/숨김이 _partHidden SSOT 공유라 .twn이 "삭제 vs 숨김" 미구분. 본 fix는 soft(재오픈 복원). 만약 "삭제=영구(.twn에서 제외)" 의도면 별도 데이터 모델(_deletedIds 블록) 신설 필요 — PM 명확화 요청
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs (ApplyTwnPayloadCore 매칭 루프 SetActive 복원)
검증
• 컴파일 + Stage 2: A 추가→Save→삭제→Open → A 복원 확인 / 회귀: 정상 Open·빈씬 Open·Duplicate 무손상

v0.1.534 — v0.1.534 — QA-149 S0048 백업 파일 신뢰성 fix (비-pickable + 멱등 + 자동 정리)

v0.1.534 v0.1.534 — QA-149 S0048 백업 파일 신뢰성 fix (비-pickable + 멱등 + 자동 정리) zip release notes GitHub
협업자 QA-149 [긴급] (v0.1.532 QC — 내 C4a 백업 코드 버그)
• 증상(PM): .pre-S0048.bak.twn 확장자가 .twn → 파일피커(*.twn) 노출 → JP가 마이그레이션 전 스냅샷 오픈 → TowerLamp(post-backup) 미복구. 백업 비-멱등(.bak.twn.bak.twn 누적). 폴더 오염
• fix (spec-implementation-judgment — PM 요청 채택 + 자동 정리 추가):
◦ (1) 비-pickable 확장자 .pre-S0048.bak(.twn 아님 → *.twn 피커 미노출, JP 오픈 차단)
◦ (2) 멱등path.Contains(".pre-S0048.bak")면 재백업 skip (.bak.bak 누적 차단)
◦ (3) 기존 .pre-S0048.bak.twn 자동 rename.pre-S0048.bak (피커 오염 + 폴더 정리. 신 백업 있으면 옛것 삭제)
• _currentTwnPath 무결성 = 백업 비-pickable+자동정리로 간접 해소(백업을 못 여니 currentPath가 백업 안 가리킴)
참고 (spec-implementation-judgment)
• S0048 마이그레이션은 비파괴적(shadow map, .twn 미변경)이라 본 백업은 C4 switchover(미구현, 비호환) 대비 사전 안전망. PM 데이터 안전 의도 존중하여 백업 유지 + 결함만 fix
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs (OpenTwnPath 백업 로직)
검증
• 컴파일 + Stage 2: 프로젝트 Open 시 .pre-S0048.bak(비-.twn) 생성 + 피커에 백업 미노출 + 기존 .bak.twn 자동 정리. 협업자 QA 백로그 (QA-130 다음)

v0.1.533 — v0.1.533 — QA-130 Alt 메뉴바 오발동 fix (held 마우스 가드 + 진단 로그)

v0.1.533 v0.1.533 — QA-130 Alt 메뉴바 오발동 fix (held 마우스 가드 + 진단 로그) zip release notes GitHub
협업자 QA-130/123/145 (PM Stage 2 진단 — 우클릭 회전 후 메뉴바 자동 활성화)
• root cause(PM 확정): _altDownTime false positive → 키보드 공백 구간(otherKey 없음)에서 Alt keyup → 메뉴바 발동
held 마우스 가드 추가: Input.anyKeyDown(기존 otherKey 검사)은 새 keydown만 잡아 우클릭 회전 중 held 마우스를 누락 → Alt window 중 마우스 버튼 held면 otherKey=true (메뉴바 차단)
진단 로그 보강(PM 명시 요청): downTime set 시 LeftAlt/RightAlt 구분 + 마우스 L/R/M held 상태 / 메뉴바 발화 시 마우스 상태 → false Alt 정체 + 우클릭 연관 확인용
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs (Alt 메뉴바 detect path 3곳 — 가드 + 로그)
검증
• 컴파일 + Stage 2 사용자/PM PC 마우스 검증 (우클릭 회전 후 WASD → 메뉴바 안 먹히는지). 로그로 root cause 확정
• Alt-단독 메뉴바 활성화는 마우스 미held 시 정상 유지(가드는 마우스 held 시에만 차단)
• S0012 통신 작업과 별개 — 협업자 QA 백로그 진입 (사용자 "다른거 자율" 지시)

v0.1.532 — v0.1.532 — C6c-b 충돌 모달 critic 중대 fix (모달 생명주기)

v0.1.532 v0.1.532 — C6c-b 충돌 모달 critic 중대 fix (모달 생명주기) zip release notes GitHub
critic 중대 fix (CONDITIONAL → PASS)
• 중대#2 (패널 Hide/재오픈 시 모달 고아·stale 클로저) → Hide()/Show()에 _modal.Hide() 추가
• 중대#1 (ConfirmModal.Build 중복 시 고아 overlay) → Build idempotent 가드(_overlay != null return)
• 치명#2 (_onConfirm stale 덮어쓰기) → ManualAssign에 _modal.IsVisible 재진입 가드(backdrop가 1차 차단, 2중 안전)
• 치명#1 (Ok 경로 RenderLeft 누락) = critic 과분석 — field가 입력값 표시라 좌측 정확, RenderRight-only는 C6c-a 의도(콜백 중 field 파괴 회피)
• 사소 (충돌 메시지 이중 dash) → "이미 사용 중"으로 정리
영향 파일
Assets/Scripts/Plc/ConfirmModal.cs (Build idempotent)
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (Hide/Show 모달 정리 + IsVisible 가드)
Assets/Scripts/Plc/PlcAddressAssigner.cs (충돌 메시지 정리)
S0048/S0012 진행
• C1~C6c-c + C6c-b(충돌 모달) = S0012 기획서 완전 충족. 6 모듈 격리 설계
• 잔존: C4 switchover(비호환, 사용자 확인). 드래그·수동·모달 UI = Stage 2 사용자 PC 마우스

v0.1.531 — v0.1.531 — S0048/S0012 C6c-b 충돌 모달 (기획서 완전 충족)

v0.1.531 v0.1.531 — S0048/S0012 C6c-b 충돌 모달 (기획서 완전 충족) zip release notes GitHub
핵심 변경
• 신규 ConfirmModal — 재사용 확인 모달(전체화면 backdrop + 중앙 다이얼로그 + 확인/취소). 순수 UI Toolkit, 도메인 무참조(격리 모듈)
• 수동 입력 충돌 시: 토스트 거부 대신 모달 "Coil X 충돌 — 다음 빈 주소 Y로 배정?" [배정]/[취소]
◦ 배정 → 제안된 다음 빈 주소로 재배정 / 취소 → field 복원
PlcAddressAssigner.AssignManualManualOutcome enum(Ok/Rejected/Conflict) + suggested(다음 빈 주소) 반환. 충돌과 무효 구분
• TowerLamp 수동은 블록 충돌 토스트(모달은 일반 포트). 모달은 _root 와 별개 sibling(Render Clear 무영향)
영향 파일
• 신규: Assets/Scripts/Plc/ConfirmModal.cs
• 수정: PlcAddressAssigner.cs(ManualOutcome enum+suggested), PlcAddressMappingPanel.cs(_modal+라우팅+ResolveConflict)
S0048/S0012 진행
• C1~C6c-c + C6c-b(충돌 모달) = S0012 기획서 완전 충족(4탭+드래그+수동+TowerLamp+충돌모달+영속). 6 모듈 격리
• DWord 2행만 생략(현재 DWord 포트 0건). 잔존: C4 switchover(비호환, 사용자 확인). 드래그·수동·모달 UI = Stage 2

v0.1.530 — v0.1.530 — C6c-c TowerLamp 할당 critic 중대 fix (Apply 대칭 + 블록 탐색 최적화)

v0.1.530 v0.1.530 — C6c-c TowerLamp 할당 critic 중대 fix (Apply 대칭 + 블록 탐색 최적화) zip release notes GitHub
critic 중대 fix (CONDITIONAL → PASS)
• 중대#1 (PlcAddressMigration.Apply TowerLamp case 비대칭) → Apply에 TowerLamp case 추가(Ch0→ModbusCoilBase, Register 대칭/방어). 편집 중 발생한 Apply 중복 1건 제거
• 중대#2 (IsBlockFree 매 start HashSet 생성 O(N×M)) → NextFreeBlock에서 UsedCoils 1회 호이스팅 + BlockFree 분리
• 치명(수동 실패 field 복원) = critic 과분석 — map Ch0 == ModbusCoilBase 항상 일치(Write가 둘 다 set)라 CurNumber 복원 정확
• 사소 (코드 헤더 이모지 3건) → 제거 (no-emoji 룰)
C6c-c 최종 (v0.1.529~530)
PlcTowerLampAssigner base+offset 격리 모듈 — 자동(연속 빈 블록)+수동(블록 충돌). ModbusCoilBase SSOT 역기록
• 뷰가 TowerLamp→_towerAssigner / 일반→_assigner 라우팅. CanAssignPort: TowerLamp Ch0만, 일반 전부
영향 파일
Assets/Scripts/Plc/PlcAddressMigration.cs (Apply TowerLamp case + 중복 제거)
Assets/Scripts/Plc/PlcTowerLampAssigner.cs (HashSet 호이스팅 + 제거)
Assets/Scripts/Plc/{PlcAddressMappingPanel,IAddressableComponent}.cs (제거)
S0048/S0012 진행
• C1~C6c-c 완료 — 4탭 에디터 + 6컴포넌트 전부(TowerLamp 포함) 할당 + 영속. S0012 핵심 spec 완결
• 5 모듈 격리 설계. 잔존: C4 switchover(비호환, 사용자 확인). 드래그·수동 UI = Stage 2

v0.1.529 — v0.1.529 — S0048/S0012 C6c-c TowerLamp base+offset 할당 (격리 모듈)

v0.1.529 v0.1.529 — S0048/S0012 C6c-c TowerLamp base+offset 할당 (격리 모듈) zip release notes GitHub
핵심 변경
• 신규 PlcTowerLampAssigner — TowerLamp base+offset(Ch0=base, Ch1+=base+i 연속 Coil 블록) 특수 할당
◦ 자동: 채널 수만큼 연속 빈 Coil 블록 탐색 → base 설정 + 채널 일괄 매핑
◦ 수동: base 입력 → 블록[base..base+N-1] 충돌 검사. ModbusCoilBase = SSOT 역기록
• 일반 포트와 다른 주소 모델이라 별도 모듈로 격리(사용자 "문제 코드만 격리" 지시 실증) — UI·엔진 무참조
CanAssignPort(comp, port) — TowerLamp는 Ch0(base)만 할당, Ch1+는 파생 표시. 일반 포트는 전부
• 뷰가 TowerLamp → _towerAssigner / 일반 → _assigner 라우팅. 일반 Assigner는 TowerLamp 방어 가드
모듈 구성 (5)
• PlcTabClassifier / PlcAddressAssigner / PortDragController / PlcTowerLampAssigner / PlcAddressMappingPanel(뷰)
영향 파일
• 신규: Assets/Scripts/Plc/PlcTowerLampAssigner.cs
• 수정: PlcAddressAssigner.cs(CanAssignPort+방어), PlcAddressMappingPanel.cs(라우팅+파생 라벨)
S0048/S0012 진행
• C1~C6c-c 완료 — 4탭 에디터 + 드래그/수동 + 6컴포넌트 전부(TowerLamp 포함) 할당 + 영속. S0012 핵심 spec 완결
• 잔존: 충돌 모달(토스트로 처리됨)·DWord(포트 0건) 생략 / C4 switchover(비호환, 사용자 확인). 드래그·수동 UI = Stage 2

v0.1.528 — v0.1.528 — 매핑 에디터 모듈 분리 critic SoC fix (Assigner 순수화)

v0.1.528 v0.1.528 — 매핑 에디터 모듈 분리 critic SoC fix (Assigner 순수화) zip release notes GitHub
핵심 변경 (거동 0 변경)
PlcAddressAssigner UnityEngine 무참조화 — Time.realtimeSinceStartupAsDouble를 뷰(Panel)가 주입 (AssignAuto/AssignManual/Write에 double ts 인자)
◦ 서비스 계층이 Factory00 + System 만 의존 → UI/엔진 결합 제거, SoC 완성 (사용자 "객체지향 분리" 지시 부합)
• 죽은 필드 _modeBtn 제거 (지역 modeBtn 클로저로 충분)
• critic 중대#2(Cancel ReleasePointer 가드)는 오판 — PortDragController Cancel 핸들러에 HasPointerCapture 가드 이미 존재
모듈 격리 최종 (v0.1.527~528)
PlcTabClassifier(분류 SSOT) / PlcAddressAssigner(할당 write — UI·엔진 무참조 순수 서비스) / PortDragController(드래그) / PlcAddressMappingPanel(뷰)
• 의존방향 단방향, 순환 없음. 한 모듈 버그 = 모듈 단위 격리·revert
영향 파일
Assets/Scripts/Plc/PlcAddressAssigner.cs (ts 주입 + UnityEngine using 제거)
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (ts 전달 + _modeBtn 제거)
체크포인트
• 빌드 archive 보존(518~527 롤백 가능). 본 빌드 = C6 에디터 모듈화 + SoC 마감
• 거동 보존 리팩토링 (C6a~C6c-a 동작 동일). 드래그·수동 UI = Stage 2 사용자 PC

v0.1.527 — v0.1.527 — S0048/S0012 매핑 에디터 객체지향 모듈 분리 (문제 코드 격리 설계)

v0.1.527 v0.1.527 — S0048/S0012 매핑 에디터 객체지향 모듈 분리 (문제 코드 격리 설계) zip release notes GitHub
핵심 변경 (거동 0 변경 — 순수 리팩토링)
• 425라인 단일 패널 → 4 모듈로 책임 분리 (사용자 지시: 문제 발생 코드만 격리되도록)
PlcTabClassifier(61) — device↔탭↔포트타입 매핑 SSOT (분류 버그 격리)
PlcAddressAssigner(88) — 할당 SSOT write(Set+Apply 역기록+발행), 충돌/빈주소 (영속 버그 격리, UI 무참조)
PortDragController(82) — 드래그 5-핸들러+capture 가드+panel.Pick (드래그 버그 격리)
PlcAddressMappingPanel(274) — 렌더링+입력 wiring(뷰)만
• 드래그=AssignAuto / 수동=AssignManual 둘 다 Assigner 단일 경로 → 영속 로직 1곳
격리 설계 효과
• UI 버그(드래그/렌더) ↔ 로직 버그(할당/충돌/영속) 상호 격리 → 회귀 시 모듈 단위 추적·revert
• 의존방향: Panel→Assigner→Classifier+Migration / DragController→콜백 (순환 없음)
영향 파일
• 신규: Assets/Scripts/Plc/{PlcTabClassifier,PlcAddressAssigner,PortDragController}.cs
• 재작성: Assets/Scripts/Plc/PlcAddressMappingPanel.cs (425→274, 뷰만)
체크포인트
• 빌드 zip archive 보존(518~526 롤백 가능). 본 빌드 = C6 에디터 모듈화 마일스톤
• 거동 보존 리팩토링 → 컴파일 + critic(SoC/거동) 검증. 드래그·수동 UI = Stage 2 사용자 PC

v0.1.526 — v0.1.526 — S0048/S0012 C6c-a 자동/수동 토글 + 수동 입력 (critic 중대 fix)

v0.1.526 v0.1.526 — S0048/S0012 C6c-a 자동/수동 토글 + 수동 입력 (critic 중대 fix) zip release notes GitHub
핵심 변경 (C6c-a = v0.1.525~526)
• 매핑 에디터 "모드: 자동/수동" 토글 — 자동=드래그 할당, 수동=IntegerField 직접 입력(Enter/blur commit)
• 수동 입력 → 충돌 검사(같은 device 중복) → 역기록 영속(Apply) + 발행. 충돌/0이하 시 복원 + 토스트
• stale 콜백 가드(_renderGen) + 좌측 field 유지(우측만 갱신)
critic 중대 fix (CONDITIONAL → PASS)
• 중대#1 (isDelayed+SetValueWithoutNotify 재진입 루프 → 스택오버플로) → _inManualAssign 재진입 가드(try/finally)
• 중대#2 (_modeBtn 클로저 desync — Render 재생성 시 구 버튼 참조) → 지역 변수 캡처
• 중간#2 (null PortKey 방어) + 중간#3 (수동 모드 "드롭 영역" 오표기 제거) 동시 처리
영향 파일
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (모드 토글 + 수동 IntegerField + ManualAssign 재진입/충돌 가드)
S0048/S0012 진행
• C1~C6b + C6c-a(자동/수동 토글 + 수동 입력) 완료 — 4탭 에디터 핵심 기능(표시/드래그/수동/영속) 완결
• 잔존: C6c-b(충돌 모달 vs 현 토스트 / DWord 2행 — 현재 DWord 포트 0건) / C6c-c(TowerLamp base+offset) / C4 full switchover(.twn 직렬화 = 비호환, 사용자 확인)
• 수동 입력 일부 키보드 자동화 가능, 드래그 = Stage 2 사용자 PC 마우스

v0.1.525 — v0.1.525 — S0048/S0012 C6c-a 자동/수동 토글 + 수동 어드레스 입력

v0.1.525 v0.1.525 — S0048/S0012 C6c-a 자동/수동 토글 + 수동 어드레스 입력 zip release notes GitHub
핵심 변경
• 매핑 에디터 헤더에 "모드: 자동/수동" 토글 — 자동=드래그 할당(C6b), 수동=IntegerField 직접 입력
• 수동 모드: 좌측 포트 행이 IntegerField(현재 주소) — Enter/blur commit(isDelayed) → 충돌 검사 → 역기록 영속(Apply) + 발행
• 충돌(같은 device 중복 주소) 또는 0 이하 → SetValueWithoutNotify 복원 + 토스트 경고
• stale 콜백 가드(_renderGen) — 재렌더 후 GC 안 된 IntegerField 발화 차단. 좌측 field 유지(콜백 중 파괴 회피) → 우측만 갱신
영향 파일
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (모드 토글 + 수동 IntegerField 분기 + ManualAssign/IsNumberUsed/CurNumber)
S0048 진행
• C1~C6b + C6c-a(자동/수동 토글 + 수동 입력) 완료. 다음 C6c-b(충돌 모달 + DWord 2행) / C6c-c(TowerLamp base+offset) / C4 switchover
• TowerLamp는 수동 모드도 제외(CanAssign — base+offset은 C6c-c). 수동 입력 키보드 검증 일부 자동화 가능, 드래그는 Stage 2

v0.1.524 — v0.1.524 — S0048/S0012 C6b 드래그 할당 (재critic 중대 정리, 클린 마감)

v0.1.524 v0.1.524 — S0048/S0012 C6b 드래그 할당 (재critic 중대 정리, 클린 마감) zip release notes GitHub
핵심 변경 (C6b = v0.1.522~524 누적)
• 4탭 매핑 에디터 드래그앤드롭 할당 — 좌측 미할당 포트 드래그 → 우측 활성 탭 → 다음 빈 주소 자동 연속 할당
• 역기록 영속 PlcAddressMigration.Apply(5종, Register 거울상) → 옛 필드 write(옛 필드 SSOT, 다음 로드 재생산, 소실 0)
• AddressMappingChangedEvent 발행 + box-select decouple + 드래그 5-핸들러(S0055 CapturePointer/pointerId 가드)
재critic 중대 정리 (CONDITIONAL → PASS)
• dc/dp 캡처를 release/ClearDrag 이전으로 이동 (동기 PointerCaptureOut 시 할당 소실 방지 — correctness)
• ClearDrag idempotent 가드 (release→CaptureOut 연쇄 이중 호출 → OnDragStateChanged 이중 발화 차단)
• AssignPort Float 포트 가드 (PortTab<0 시 잘못된 device 등록 차단)
• 직전 치명#1(TowerLamp 소실)·치명#2(capture leak) 해소 확인 + Apply↔Register 6/5/4/4/1 전수 대칭 확인
영향 파일
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (드래그+좌측+할당 + critic 2-pass fix)
Assets/Scripts/Plc/PlcAddressMigration.cs (Apply 역기록)
Assets/Scripts/Game/Factory00Bootstrap.cs (wiring + box-select 가드)
S0048 진행
• C1~C5 + C6a(표시) + C6b(드래그 할당, critic 치명 0 중대 0) 완료. 다음 C6c(수동입력/자동수동토글/충돌모달/DWord 2행/TowerLamp base+offset)
• 드래그 시각검증 = Stage 2 사용자 PC 마우스 (헤드리스 자동화 외 — qa-standard-workflow §3)

v0.1.523 — v0.1.523 — S0048/S0012 C6b 드래그 할당 + critic 치명/중간 fix

v0.1.523 v0.1.523 — S0048/S0012 C6b 드래그 할당 + critic 치명/중간 fix zip release notes GitHub
핵심 변경
• 4탭 매핑 에디터 드래그앤드롭 할당 — 좌측 미할당 포트 드래그 → 우측 활성 탭 → 다음 빈 주소 자동 연속 할당
• 역기록 영속 PlcAddressMigration.Apply(5종, Register 거울상) → 옛 필드 write(옛 필드 SSOT, 다음 로드 재생산)
• AddressMappingChangedEvent 발행 + box-select decouple(_plcMappingDragActive) + 드래그 5-핸들러(S0055 가드)
critic 코드리뷰 fix (FAIL → 처리)
• 치명#1 (TowerLamp Ch 드래그 → Apply no-op 소실) → CanAssign 가드: TowerLamp 포트 드래그 제외("미할당 — C6c" 비드래그 표시). base+offset은 C6c
• 치명#2 (PointerCancel capture leak) → Cancel 핸들러에서 HasPointerCapture 시 ReleasePointer
• 중간#1 (드래그 중 탭 전환 → 잘못된 device) → AssignPort device = 포트 고유 TabDevice(PortTab(port))
• 중간#2 (재진입 이중 캡처) → PointerDown _dragActive 가드
• 중대#3(Rotary Home 누락) = critic 오판(L83 존재, Apply↔Register 6/5/4/4/1 전부 대칭) / 중대#1·#2 = 저위험 수렴
영향 파일
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (드래그+좌측+할당 + critic fix)
Assets/Scripts/Plc/PlcAddressMigration.cs (Apply 역기록)
Assets/Scripts/Game/Factory00Bootstrap.cs (wiring + box-select 가드)
검증
• 컴파일 PASS 목표. 드래그 시각검증 = Stage 2 사용자 PC 마우스. 다음 C6c(수동입력/토글/충돌모달/DWord/TowerLamp base+offset)

v0.1.522 — v0.1.522 — S0048/S0012 C6b 드래그 어드레스 할당 + 역기록 영속

v0.1.522 v0.1.522 — S0048/S0012 C6b 드래그 어드레스 할당 + 역기록 영속 zip release notes GitHub
핵심 변경
• 4탭 매핑 에디터 드래그앤드롭 할당 — 좌측 미할당 포트를 우측 활성 탭으로 드래그 → 다음 빈 주소 자동 연속 할당
• 좌측 = 활성 탭 device 일치 포트만(Bit→출력/Coil, Word→데이터출력/HoldingRegister). 미할당=드래그 / 할당=주소 표시
• 역기록 영속: PlcAddressMigration.Apply(Register 거울상, 5종) → 옛 필드 write → 다음 로드 populate 재생산(소실 0, 옛 필드 SSOT)
AddressMappingChangedEvent 발행 + 자동 연속 할당(1부터, device별 빈 슬롯)
• 드래그 5-핸들러(구식 패널 이식 + S0055 CapturePointer/pointerId 가드) + panel.Pick hit-test + box-select decouple(_plcMappingDragActive)
사이클 분할 (C6c 이월)
• 수동 입력 + 자동/수동 토글 + 충돌 모달 + DWord 2행 + TowerLamp base+offset + 실시간값
• 탭 입력/데이터입력(DiscreteInput/InputRegister)은 옛 필드 backing 없어 비노출(C4 직렬화 후 영속 가능)
영향 파일
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (드래그 + 좌측 포트행 + 할당 재작성)
Assets/Scripts/Plc/PlcAddressMigration.cs (Apply 역기록 writer +52라인)
Assets/Scripts/Game/Factory00Bootstrap.cs (OnDragStateChanged/OnToast wiring + box-select 가드)
검증
• 컴파일 PASS 목표. 드래그 동작 시각검증 = Stage 2 사용자 PC 마우스 (헤드리스 자동화 외)
• spec S0012 r006 §3 드래그 자동할당 / S0048 §6. spec WHAT 충족, HOW 코드 최적

v0.1.521 — v0.1.521 — S0048/S0012 C6a 4탭 매핑 에디터 + critic 치명/중대 fix

v0.1.521 v0.1.521 — S0048/S0012 C6a 4탭 매핑 에디터 + critic 치명/중대 fix zip release notes GitHub
핵심 변경
• 신규 PlcAddressMappingPanel 4탭 PLC 어드레스 매핑 에디터 (출력/입력/데이터출력/데이터입력) — 컴포넌트 Inspector "통신 어드레스 설정" 버튼이 여는 표시 UI
• 좌측 컴포넌트 목록(6종) + 우측 활성 탭 매핑 표 (주소/포트/컴포넌트) — _plcAddressMap(SSOT) 조회. classifyTab = Device→탭
OpenAddressMappingEditorEvent 구독 → lazy build + Show. 명명 핸들러 → OnDestroy 해제
critic 코드리뷰 fix (CONDITIONAL → 처리)
• 치명#1 (구식 ModbusAddressMappingPanel 동좌표 겹침) → 상호 배타 Hide 배선 (새 패널 열 때 구식 Hide / 구식 열 때 새 패널 Hide)
• 중대#1 (표시 레이어가 SSOT mutate, SoC) → 패널 Register 호출 제거 → Bootstrap 핸들러에서 PopulatePlcAddressMapFromLegacyFields 선행 (패널 순수 표시)
• 치명#2(Render-on-Show 리셋)=오판(_activeTab 필드 유지) / 중대#2(Vacuum 비대상)·#3(Modbus 의존)·#4=scope·defer
영향 파일
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (신규)
Assets/Scripts/Game/Factory00Bootstrap.cs (필드 + Awake 구독 + 명명 핸들러 + OnDestroy 해제 + 구식버튼 Hide)
S0048 진행
• C1~C5 + C6a(4탭 에디터 표시, critic PASS) 완료. 다음 C6b(드래그앤드롭 할당 + 자동 연속 할당)
• spec S0012 r006 §3 / S0048 §6. spec WHAT 충족, HOW 코드 최적 (spec-implementation-judgment)

v0.1.520 — v0.1.520 — S0048/S0012 C6a 4탭 PLC 어드레스 매핑 에디터 (표시)

v0.1.520 v0.1.520 — S0048/S0012 C6a 4탭 PLC 어드레스 매핑 에디터 (표시) zip release notes GitHub
핵심 변경
• 신규 PlcAddressMappingPanel — 컴포넌트 Inspector "통신 어드레스 설정" 버튼이 여는 4탭 에디터 (출력/입력/데이터출력/데이터입력)
• 좌측 컴포넌트 목록(6종 IAddressableComponent) + 우측 활성 탭 매핑 표 (주소/포트/컴포넌트) — _plcAddressMap(SSOT) 조회
• classifyTab = ModbusPlcAddress.Device → 탭 (Coil=출력 / DiscreteInput=입력 / HoldingRegister=데이터출력 / InputRegister=데이터입력)
OpenAddressMappingEditorEvent 구독 (C5 설정 버튼 발행) → lazy build + Show. 명명 핸들러 → OnDestroy 해제
• C6a = 표시/탭전환만. 드래그 할당=C6b / 충돌 모달·DWord 2행·실시간값=C6c
영향 파일
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (신규 193라인)
Assets/Scripts/Game/Factory00Bootstrap.cs (필드 + Awake 구독 + 명명 핸들러 + OnDestroy 해제 ~22라인)
S0048 진행
• C1~C5 + C6a(4탭 에디터 표시) 완료. 다음 C6b(드래그앤드롭 할당 + 자동 연속 할당)
• 신규 패널 = 구식 ModbusAddressMappingPanel 병존 (C6c switchover 시 제거)
• spec S0012 r006 §3 4탭 + S0048 §6. spec WHAT(4탭 표시/PlcAddressMap SSOT) 충족, HOW(신규 클래스)는 코드 최적 (spec-implementation-judgment)

v0.1.519 — v0.1.519 — S0048 C5 Inspector 통신 어드레스 read-only 섹션 + 설정 버튼 (additive)

v0.1.519 v0.1.519 — S0048 C5 Inspector 통신 어드레스 read-only 섹션 + 설정 버튼 (additive) zip release notes GitHub
핵심 변경
• 컴포넌트 Inspector에 "통신 어드레스 (read-only)" 섹션 추가 — Protocol + 포트별 매핑 주소(PlcAddressMap 조회, DisplayLabel) / 미할당 회색
• "통신 어드레스 설정 ▼" 버튼 → OpenAddressMappingEditorEvent 발행 (에디터 구독 S0012/S0049는 C6 후속 — 현재 토스트만)
• 공통 헬퍼 RenderAddressSection(card, comp) 1개 + 6 카드(Servo/Rotary/Pneumatic×2/PhotoSensor/TowerLamp) 호출
• 렌더 직전 컴포넌트별 PlcAddressMigration.Register 즉석 호출 → 라이브 옛 필드값 반영(stale 회피)
additive: 기존 편집형 Coil/Register 필드 유지(병존). read-only 섹션을 그 아래 추가. 편집형 제거는 switchover(후속)
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs (RenderAddressSection 헬퍼 + 6 카드 1줄씩)
S0048 진행
• C1~C4a + C5(Inspector read-only 표시) 완료. 다음 C6(4탭 매핑 에디터 화면 — 설정 버튼이 여는 실제 UI, S0012)
• C5 = additive(기존 편집필드 병존) → 빌드 컴파일 + 시각 검증
• spec §6 read-only 섹션. spec static 싱글톤 → Bootstrap 인스턴스 필드 adapter (spec-implementation-judgment)

v0.1.518 — v0.1.518 — S0048 C4a 어드레스 마이그레이션 등록 + .twn 백업 (additive shadow)

v0.1.518 v0.1.518 — S0048 C4a 어드레스 마이그레이션 등록 + .twn 백업 (additive shadow) zip release notes GitHub
핵심 변경
• 옛 modbusCoil*/Register* 필드 → 중앙 PlcAddressMap 등록 (런타임 shadow). @Obsolete 병존 — 옛 필드 active 유지
PlcAddressMigration 중앙 클래스 (6 컴포넌트 포트→옛필드 매핑, value=0 skip)
• Bootstrap: _plcAddressMap 필드 + PopulatePlcAddressMapFromLegacyFields()(로드 후 1패스) + .twn 1회 백업(.pre-S0048.bak.twn, idempotent)
.twn 직렬화 X — 매 로드 시 옛 필드에서 재populate(옛 필드 SSOT, reopen 안전). 기존 동작 0 변경
• 사용자 승인 "@Obsolete 병존 / 권장"
영향 파일
Assets/Scripts/Plc/PlcAddressMigration.cs (신규)
Assets/Scripts/Game/Factory00Bootstrap.cs (_plcAddressMap + Populate + 백업 + 호출)
S0048 진행
• C1~C3 + C4a(등록+백업) 완료. 다음 C4b(@Obsolete 마킹 + #pragma 정당 소비처) → C5(Inspector read-only) → C6(4탭 매핑 에디터)
• C4a = additive shadow(기존 동작 0 변경) → self-review + 빌드 검증

v0.1.517 — v0.1.517 — S0048 C3 부품 PLC 포트 추상화 (IAddressableComponent + 6 컴포넌트, additive)

v0.1.517 v0.1.517 — S0048 C3 부품 PLC 포트 추상화 (IAddressableComponent + 6 컴포넌트, additive) zip release notes GitHub
핵심 변경
• 각 시뮬 컴포넌트가 PLC 포트 목록(Ports)을 노출 — 중앙 매핑(C1 PlcAddressMap)이 (ComponentId,PortName)으로 주소 배정할 토대
• 신규 IAddressableComponent + PlcPortDefinition + PortDirection/PortDataType (Factory00.Plc)
• 6 컴포넌트: ServoAxis(6포트) / Rotary(5) / PneumaticCyl(4) / PneumaticRotary(4) / PhotoSensor(1) / TowerLamp(동적 ChN)
additive: 기존 modbusCoil*/Register* 필드 유지, Ports는 getter(직렬화 X → .twn 바이트 무영향). 소비처(ActuatorPlcBridge/SignalSimulator/Inspector) 무손상. 필드 폐기는 C4
• 방향(Dir) = ActuatorPlcBridge ground-truth 검증: Coil=PLC→Sim=Input, Register=Sim→PLC=Output
영향 파일
Assets/Scripts/Plc/IAddressableComponent.cs (신규)
Assets/Scripts/Actuators/{ServoAxis,Rotary,PneumaticCylinder,PneumaticRotaryCylinder}Actuator.cs + Sensors/PhotoSensorComponent.cs + Outputs/TowerLampComponent.cs
S0048 진행
• C1(모델)+C2(이벤트)+C3(컴포넌트 포트) 완료. 다음 C4(옛 필드 폐기 + .twn 자동변환 = 비호환, 기획서 Q-2/Q-6 승인분) → C5(Inspector 읽기전용) → C6(4탭 매핑 에디터)
• Vacuum 3종 제외(Coil 필드 없음, P2) · PhotoSensor Diag 제외(코드에 필드 없음) — spec-implementation-judgment

v0.1.516 — v0.1.516 — S0048 C2 어드레스 인디렉션 이벤트 4종 (additive, S0048 코어 foundation 완결)

v0.1.516 v0.1.516 — S0048 C2 어드레스 인디렉션 이벤트 4종 (additive, S0048 코어 foundation 완결) zip release notes GitHub
핵심 변경
• S0048 어드레스 인디렉션 이벤트 레이어 (신규 파일만, additive, 기존 코드 0 수정)
• 4종: OpenAddressMappingEditorEvent(AddressMappingContext) / AddressMappingChangedEvent(IPlcAddress Old/New) / ProtocolChangedEvent / PortSignalChangedEvent
• EventBus 3곳 등록 (event/Publish/Reset). C1(데이터 모델)+C2(이벤트) = S0048 코어 foundation 레이어 완결
• spec §5. Factory00.Plc(C1) 참조. 구독/발행 배선은 C5/C6(Inspector·매핑 에디터)
영향 파일
Assets/Scripts/Events/PlcAddressEvents.cs (신규) + EventBus.cs (3곳 등록)
S0048/S0055 진행 + 자율 보류
• S0048 C1+C2(모델+이벤트 코어) 완결 · S0055 P1 완결. 자율-safe additive 영역 소진.
• 자율 보류 — 남는 전부 사용자 결정 게이트: S0048 C3(컴포넌트 Ports 침습)/C4(actuator 폐기=비호환 50참조) · S0055 P2(패널 부착 침습) · MC Protocol 재확인 · Stage 2
• C2 = 단순 additive 패턴 미러 → self-review + 빌드 EventBus reg 검증 (full critic는 복잡 파트만)

v0.1.515 — v0.1.515 — S0055 C3 ResizableWindowController (서브윈도우 리사이즈 P1 완결, additive)

v0.1.515 v0.1.515 — S0055 C3 ResizableWindowController (서브윈도우 리사이즈 P1 완결, additive) zip release notes GitHub
핵심 변경
• S0055 서브윈도우 이동/리사이즈 P1 완결 — ResizableWindowController 컴포지션 부착 헬퍼 (어느 패널에도 미부착, additive)
• 타이틀바 드래그 이동(화면경계 클램프, 타이틀바 일부 노출 Q-4) + 8방향 리사이즈 핸들(4모서리+4가장자리, Min/Max 클램프 0=무제한, 좌/상 가장자리 위치 보정)
• PlayerPrefs 영속화(PointerUp 1회 Save) + SubWindowLayoutChangedEvent/ResetEvent 발행 + 오픈 시 복원
• 드래그 패턴 = 좌패널 splitter 미러(PointerDown button0 + CapturePointer + Move Clamp + Up Save + Cancel 안전망)
• spec 상속 → POCO 패널 컴포지션 부착형 deviation. drag-select 차단은 onDragStateChanged 콜백 decouple. 커서 전환 P3.
영향 파일
Assets/Scripts/UI/ResizableWindowController.cs (신규 205라인)
S0055 진행
• P1(C1 이벤트+모델 / C2 Store / C3 Controller) 완결 — additive 자율-safe 전부 완료. full critic 검토.
• P2(기존 4 패널 부착 = 침습적: 포커스/ESC/drag-select 횡단 회귀 + 마우스 Stage 2 검증)는 사용자 결정 게이트
• 이후 자율 영역 소진 → S0048 3결정 + C4 비호환 / S0055 P2 / MC Protocol 재확인 / Stage 2 통합 결정 큐

v0.1.514 — v0.1.514 — S0055 C1+C2 서브윈도우 레이아웃 이벤트 + 모델 + Store (additive)

v0.1.514 v0.1.514 — S0055 C1+C2 서브윈도우 레이아웃 이벤트 + 모델 + Store (additive) zip release notes GitHub
핵심 변경
• S0055 서브윈도우 리사이즈/이동 P1 인프라 1/2 (신규 파일만, additive, 기존 코드 0 수정)
• 이벤트 2종 SubWindowLayoutChangedEvent/SubWindowLayoutResetEvent (PanelResizedEvent 패턴 미러) + EventBus 3곳 등록
• 데이터 모델 SubWindowLayout struct + IResizableWindow 인터페이스 (윈도우별 MinSize/MaxSize/Default)
SubWindowLayoutStore (PlayerPrefs 영속화 — 기존 factory00.* UI 레이아웃 패턴 재사용, 키 factory00.subwin..{x,y,w,h})
영향 파일
Assets/Scripts/Events/SubWindowEvents.cs (신규) + EventBus.cs (3곳 등록)
Assets/Scripts/UI/SubWindowLayout.cs + SubWindowLayoutStore.cs (신규)
S0055 진행
• C1(이벤트+모델)+C2(Store) 완료. C3(ResizableWindowController 드래그+8핸들 리사이즈+클램프, 복잡)는 다음 focused 사이클(full critic).
• P2(기존 4 패널 부착 = 침습적: 포커스/ESC/drag-select 횡단 회귀 + 마우스 Stage 2 검증)는 사용자 결정 대기
• spec 상속 가정 → factory00 POCO 패널엔 컴포지션 부착형 deviation (spec-implementation-judgment)
• C1+C2 = 단순 additive 패턴 미러 → self-review + 빌드 EventBus reg 검증 (full critic는 C3 복잡 파트 집중)

v0.1.513 — v0.1.513 — S0048 C1 PLC 어드레스 인디렉션 코어 모델 (additive)

v0.1.513 v0.1.513 — S0048 C1 PLC 어드레스 인디렉션 코어 모델 (additive) zip release notes GitHub
핵심 변경
• S0012 4탭 매핑 에디터의 prerequisite — 중앙 PLC 어드레스 매핑 SSOT 코어 (신규 파일만, additive, 기존 빌드 영향 0)
IPlcAddress(protocol 추상) + PlcProtocol enum + PortKey(ComponentId,PortName) struct + PlcAddressMap(Dictionary SSOT + 역방향 조회 + Protocol 캡슐화) + ModbusPlcAddress(IPlcAddress 구현)
• spec S0048 §4-2/4-3. record→readonly struct / ScriptableObject→plain class (Unity C#9 안전 + 코드베이스 ModbusAddressMap 패턴 정합, spec-implementation-judgment)
• 의존방향 Modbus→Plc 단방향(Plc 코어는 Modbus 무참조, SoC)
critic 2-pass
• 치명 #1: spec명 ModbusAddress가 기존 live Factory00.Plc.ModbusAddress(ModbusTcpAdapter, 9파일 참조)와 충돌 → ModbusPlcAddress 리네임 fix
• 중대 #1: PlcAddressMap.Protocol public field → {get; private set;} + SetProtocol(변경 시 매핑 초기화) 캡슐화
영향 파일
Assets/Scripts/Plc/IPlcAddress.cs + PlcAddressMap.cs (신규)
Assets/Scripts/Communication/Modbus/ModbusPlcAddress.cs (신규)
S0048/S0012 진행
• C1(코어 모델) 완료. C2(이벤트 3종)/C3(컴포넌트 Ports) 후속. C4(actuator Coil*/Register* 폐기=비호환, 50참조) 사용자 명시 대기
• 사용자 결정 큐: Q1(S0048+S0012 통합/분리 cap) · Q2(즉시폐기/@Obsolete) · Q3(MX 공유 베이스)

v0.1.512 — v0.1.512 — S0054 MC Protocol(SLMP 3E) 독립 TCP 드라이버 신규

v0.1.512 v0.1.512 — S0054 MC Protocol(SLMP 3E) 독립 TCP 드라이버 신규 zip release notes GitHub
핵심 변경
미쓰비시 PLC를 MELSOFT 무관 순수 TCP/IP(SLMP 3E)로 직접 read/write — MX(MxBridge COM 경유)와 별개 기술, 브리지 불필요, Ethernet 모듈 직접 접속
• 8 파일 신규: 디바이스코드+파싱 / 3E 프레임 encode·decode / 이벤트 5종 / IMcClient / TcpClient(실) / MockClient / DeviceMap / Component(폴링·재연결·쓰기)
골든 프레임 13/13 PASS — handoff-002 QJ71E71-100 실측 프레임 + checklist BuildBatchReadWord(0xA8,100,5) byte 단위 일치
• 비트 쓰기(Cmd 0x1401 Subcmd 0x0001) + 가변 AccessRoute(NetworkNo/StationNo) + 충돌 감지(동일 Host/Port/Net/Station) + Device "D100" 문자열 이벤트
• handoff-002/003 실측 함정 반영: ReceiveTimeout / 부분수신 누적 / 더미 SD0 read 검증(ICMP 금지) / 메인스레드 마샬링
영향 파일
Assets/Scripts/Communication/Mitsubishi/McProtocol/*.cs (8 신규)
Tools/McProtocol/McGoldenTest.cs + run-golden.sh (골든 standalone 검증 SSOT)
S0054 진행
• critic 2-pass(1차 치명3+중대6 → 8파일 rework → 2차 재검증) + 골든 standalone 검증
mock 모드 default — 실 PLC/시뮬 부재 시 폴링·EventBus·변화감지 검증. 실 TCP read/write는 Ethernet 모듈 또는 SLMP 시뮬 단계(checklist 2단계 PM)
• MX(S0011)는 GX Simulator2로 실 통신 검증 가능(별 경로) — Stage 2 진행

v0.1.511 — v0.1.511 — MX Component auto-launch (UseMock=false 시 MxBridge.exe 자동 실행, default off)

v0.1.511 v0.1.511 — MX Component auto-launch (UseMock=false 시 MxBridge.exe 자동 실행, default off) zip release notes GitHub
핵심 변경
MitsubishiPlcDriverComponent: AutoLaunchBridge(default false) + LaunchBridge() — UseMock=false + AutoLaunchBridge 시 factory00.exe 옆 MxBridge/MxBridge.exe 자동 실행. Stop 시 kill.
IsBridgeRunning() TCP 체크 → orphan/수동 브리지 재사용(중복 spawn / port 충돌 회피, critic 중대 #1·#2).
MxBridge.exe: Log → mxbridge.log 파일 출력(CreateNoWindow auto-launch 진단 경로, critic 중대 #3).
• default off = 기존 mock/수동 경로 완전 불변(additive). spec "UseMock=false 전환만" 의도 정합.
영향 파일
Assets/Scripts/Communication/Mitsubishi/MitsubishiPlcDriverComponent.cs — AutoLaunchBridge + LaunchBridge + IsBridgeRunning
Tools/MxBridge/MxBridge.cs — Log 파일 출력

v0.1.510 — v0.1.510 — MX Component 실 통신 브리지(MxBridge.exe) 빌드 배포 번들

v0.1.510 v0.1.510 — MX Component 실 통신 브리지(MxBridge.exe) 빌드 배포 번들 zip release notes GitHub
핵심 변경
MxBridge.exe 신규 (x86, ActUtlTypeLib early binding) — Unity Mono COM 불가 우회. ActUtlType COM ↔ Unity TCP 7788 텍스트 프로토콜.
Builds/Win64/MxBridge/ 번들: MxBridge.exe + ActUtlTypeLib.dll + launch-mxbridge.bat.
• 실 PLC 통신 절차: launch-mxbridge.bat 실행 → Communication Setting Utility 에서 GX Simulator/실 PLC 논리국번 구성 → Inspector MX Component Driver UseMock=false → Play.
• 검증: PING/PONG + RECONNECT→Open()=0xF0000002(통신설정 미구성 정상 에러코드). 실 read/write 는 국번 구성(GUI) 후.
영향 파일
Tools/MxBridge/MxBridge.cs (신규 호스트) + Tools/MxBridge/build-mxbridge.sh
Builds/Win64/MxBridge/ (배포 번들)

v0.1.509 — v0.1.509 — QA-102 B-03 파라미터 값 변경 Ctrl+Z/Y (FloatField + 슬라이더)

v0.1.509 v0.1.509 — QA-102 B-03 파라미터 값 변경 Ctrl+Z/Y (FloatField + 슬라이더) zip release notes GitHub
핵심 변경
QA-102 B-03 (파라미터 값 변경 Ctrl+Z/Y 미대응, v0.1.500 부분 NG): 컴포넌트 추가/삭제 Undo 는 동작하나 파라미터 값 편집(거리/각도/SensingDistance 등)은 미대응.
fix (필드 헬퍼 레벨 — 전 파라미터 필드 일괄 적용):
SensorFloatField(52 사용처) — commit(Blur/Enter) 시 ComponentEditCommand PushExecuted. lastVal 로 다중 편집 추적.
SensorSliderRow 슬라이더 — PointerDown 시작값 capture → PointerUp 에 1 command coalesce (드래그당 1 undo, live setter 유지).
SensorSliderRow valField — evt.previousValue(슬라이더 SetValueWithoutNotify 정합) → command.
ComponentEditCommand 재사용(DRY, 신규 클래스 X) + PushExecuted(편집 시 re-render 없음 → 필드 destroy 회피, undo/redo만 re-render).
검증
• 컴파일 + 캡처 회귀. 파라미터 편집 후 Ctrl+Z/Y 복원은 Stage 2 사용자 PC.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — SensorFloatField/SensorSliderRow 파라미터 undo (ComponentEditCommand 재사용)

v0.1.508 — v0.1.508 — QA-102 B-01 Alt 2-state mnemonic + B-02 최근 프로젝트 hover cascade

v0.1.508 v0.1.508 — QA-102 B-01 Alt 2-state mnemonic + B-02 최근 프로젝트 hover cascade zip release notes GitHub
핵심 변경
QA-102 B-01 (Alt mnemonic 2-state 미구현, v0.1.500 부분 NG): Alt+글자 동시는 동작하나, Windows 표준 2-state(① Alt 단독 → 메뉴바 진입 ② 그 상태에서 단일 글자로 메뉴 open)의 ②가 누락.
fix: 메뉴바 헤더 focus(=메뉴 모드, Alt 단독 진입 후) 상태에서 단일 글자(F/E/V/C/R/T/H) → ShowLnbDropdown(idx). Alt 동시 누름 불필요. 카메라 단일 키는 IsAnyUIFocused 가드로 이미 차단되어 충돌 없음.
QA-102 B-02 (최근 프로젝트 ▶ hover 미동작, v0.1.500 NG): ▶는 Ribbon.uxml 존재하나 클릭만 하위메뉴 출현(hover 미동작).
fix: cmd-recent 에 PointerEnter(hover) 핸들러 추가 → 하위메뉴 cascade. 버튼 우측에 표시(Windows 표준 cascading submenu). ShowRecentSubmenu 헬퍼 추출(click+hover 공유) + _recentSubmenuOpen 가드(hover 깜빡임 회피) + CloseContextMenu 리셋.
검증
• 컴파일 + 캡처 회귀. Alt 단독→글자 메뉴 / 최근 프로젝트 hover cascade 는 Stage 2 사용자 PC.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — Alt 2-state 메뉴 모드 라우팅 + 최근 프로젝트 hover submenu

v0.1.507 — v0.1.507 — QA-126 R-7 REAL FIX: 씬 ON 효과 raw 즉시 (딜레이 분리 완결)

v0.1.507 v0.1.507 — QA-126 R-7 REAL FIX: 씬 ON 효과 raw 즉시 (딜레이 분리 완결) zip release notes GitHub
핵심 변경
QA-126 R-7 (OnDelay 시 씬 ON 효과까지 지연 — v0.1.493 재NG): v0.1.493 에서 SensorDetectedEvent(Raw 즉시) 발행은 분리했으나, 씬 시각화(PhotoSensorVisualizer)가 여전히 딜레이 후 FinalOutput 참조 → 씬 ON 효과 지연 잔존.
root cause (PM 진단 정합): PhotoSensorVisualizer L103 effOn = (NC)? !FinalOutput : FinalOutput — 딜레이+ContactType 반영된 FinalOutput 기반.
REAL FIX: 씬 ON 효과를 raw 감지(RawDetected) 즉시 기반으로 교체. SensorVisualizationData 에 RawDetected 추가 + GetGizmoData 설정 + visualizer effOn = d.RawDetected.
◦ JP 명시: "씬은 물체를 검출하자마자 ON 효과, 실제 신호(PLC 출력)만 온딜레이." 딜레이+ContactType 은 PLC 신호(SensorStateChangedEvent → SensorPlcBridge)에만 적용 — 분리 완결.
검증
• 컴파일 + 캡처 회귀. OnDelay 500ms 시 씬 cone 즉시 ON / 출력·coil 딜레이 후는 Stage 2 사용자 PC.
영향 파일
Assets/Scripts/Sensors/ISensor.cs — SensorVisualizationData.RawDetected
Assets/Scripts/Sensors/PhotoSensorComponent.cs — GetGizmoData RawDetected
Assets/Scripts/Sensors/PhotoSensorVisualizer.cs — effOn = d.RawDetected

v0.1.506 — v0.1.506 — QA-142 뷰 메뉴 단축키 라벨 + QA-141 종료 팝업 버튼 시인성/hover

v0.1.506 v0.1.506 — QA-142 뷰 메뉴 단축키 라벨 + QA-141 종료 팝업 버튼 시인성/hover zip release notes GitHub
핵심 변경
QA-142 (뷰 메뉴 카메라 프리셋 단축키 표기 누락 + F5 충돌): F-key 바인딩은 이미 정확(F4=시점모드, F5~F8=프리셋, CameraViewController L203~223). 리본 라벨만 불일치.
fix (Ribbon.uxml): 시점모드 토글 "F5"→"F4" 정정(정면 F5 충돌 해소) + 정면 F5 / 오른쪽 F6 / 위 F7 / 등각 F8 라벨 추가. 뒤/왼쪽/아래는 미할당(라벨 없음).
QA-141 (종료 팝업 버튼 시인성/hover): M-01 종료 팝업(QA-103) 취소 버튼 흰배경+흰텍스트로 안 보임 + hover 피드백 부재.
fix (ShowQuitConfirmDialog MakeBtn): 평상시 = 어두운 배경(bgInner) + 화이트 텍스트 + 테두리(primary=gold). hover = 밝은(gold) 배경 + 블랙 텍스트 + 굵은 gold 테두리(glow 근사). PointerEnter/Leave 콜백. 취소 버튼 가독성 확보.
검증
• 컴파일 + 캡처 회귀. 라벨/버튼 hover 실 표시는 Stage 2 사용자 PC.
영향 파일
Assets/UI/Components/Ribbon.uxml — 뷰 메뉴 단축키 라벨 (F4/F5~F8)
Assets/Scripts/Game/Factory00Bootstrap.cs — MakeBtn 시인성 + hover

v0.1.505 — v0.1.505 — QA-138 뒤/왼/아래 카메라 입력 dead fix + QA-135 Lit 동기화 부작용 fix

v0.1.505 v0.1.505 — QA-138 뒤/왼/아래 카메라 입력 dead fix + QA-135 Lit 동기화 부작용 fix zip release notes GitHub
핵심 변경
QA-138 [긴급] (뒤/왼쪽/아래 시점 전환 후 카메라 조작 전면 불가, v0.1.500 QC 신규): PM 단서 = 단축키 할당 4종(정면/오른쪽/위/등각=F5~F8) 정상, 미할당 3종(뒤/왼쪽/아래) NG.
root cause (코드 추적 — PM 힌트보다 정밀): v0.1.489 신설 Back/Left/Bottom enum 이 CameraViewController.Update 의 mode dispatch switch 누락 → _mode=Back/Left/Bottom 일 때 UpdateOrbit/UpdateFirstPerson 어느 것도 미호출 → 카메라 입력 핸들러 dead.
fix: Back/Left/Bottom 을 UpdateOrbit case 에 추가 (정상 4종과 동일 orbit 처리).
QA-135 재오픈 (Lit 동기화 부작용): v0.1.500 흰색 fix(Open 재임포트 Unlit 강제)가 사용자 Lit 모드 상태와 불일치 → 로드 후 Lit 옵션 꺼진 듯 보임.
fix: 재임포트 직후 SetLitMode(_litMode) 호출 → Lit ON 이면 SwapToLitShader 로 재임포트 mat 도 Lit 동기화 (흰색 해소 유지 + Lit 상태 정합).
검증
• 컴파일 + 캡처 회귀. 카메라 입력(뒤/왼/아래 전환 후 orbit/WASD) + 로드 후 Lit 상태는 Stage 2 사용자 PC.
영향 파일
Assets/Scripts/Game/CameraViewController.cs — Update dispatch Back/Left/Bottom → UpdateOrbit
Assets/Scripts/Game/Factory00Bootstrap.cs — Open 재임포트 후 SetLitMode(_litMode)

v0.1.504 — v0.1.504 — QA-086 두 번째 서브창 z-order 최상위 (SNB 뒤 숨김 fix)

v0.1.504 v0.1.504 — QA-086 두 번째 서브창 z-order 최상위 (SNB 뒤 숨김 fix) zip release notes GitHub
핵심 변경
QA-086 (서브윈도우 z-order — SNB 뒤 숨김): 첫 서브창(OpenPartInSubWindow L8785)은 v0.1.404 에서 BringToFront() 보유하나, 두 번째 서브창(L9115)은 root.Add 후 BringToFront 누락 → hud-root/메뉴바 BringToFront 후 그 뒤에 숨김.
fix: 두 번째 서브창도 root.Add 직후 BringToFront() 추가 (첫 서브창 미러). 모달 overlay 항상 최상위.
참고: "이동·리사이즈 미지원"은 별도 기능 영역(본 fix는 z-order 한정).
검증
• 컴파일 + 캡처 회귀. z-order 최상위는 Stage 2 사용자 PC(서브창 열고 SNB 위 표시 확인).
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — 두 번째 서브창 BringToFront 추가

v0.1.503 — v0.1.503 — QA-097 서브창 씬 클릭 시 미닫힘 fix (MouseDownEvent → PointerDownEvent)

v0.1.503 v0.1.503 — QA-097 서브창 씬 클릭 시 미닫힘 fix (MouseDownEvent → PointerDownEvent) zip release notes GitHub
핵심 변경
QA-097 (서브창 씬 클릭 시 미닫힘 — SNB 클릭만 닫힘): 서브윈도우(모달 full-screen overlay) backdrop 클릭 시 닫기가 MouseDownEvent 사용 → UI Toolkit 6 에서 씬 영역(카메라 렌더 위) backdrop 클릭에 불안정 발화.
root cause (코드 추적): backdrop 콜백 MouseDownEvent (레거시) → 씬 영역 클릭 시 미발화. raw-input 3D pick 은 모달 overUI=true 로 이미 skip → 결과적으로 씬 클릭이 아무 동작 안 함(서브창 유지).
fix: backdrop 콜백 2곳(OpenPartInSubWindow + 2종) MouseDownEventPointerDownEvent (M-01 다이얼로그 동일 패턴, UI Toolkit 6 신뢰). pickingMode=Position 전체 영역 backdrop → 씬/SNB 어디 클릭이든 닫기.
검증
• 컴파일 + 캡처 회귀. 서브창 열고 씬 클릭 시 닫힘은 Stage 2 사용자 PC(마우스).
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — 서브창 backdrop MouseDownEvent → PointerDownEvent (2곳)

v0.1.502 — v0.1.502 — QA-133 씬 우클릭 컨텍스트 메뉴 뷰 라벨 정합 (리본 SSOT)

v0.1.502 v0.1.502 — QA-133 씬 우클릭 컨텍스트 메뉴 뷰 라벨 정합 (리본 SSOT) zip release notes GitHub
핵심 변경
QA-133 (씬 우클릭 컨텍스트 메뉴 뷰 라벨 오표기): 컨텍스트 메뉴(디폴트[F1]/평면도[F2]/측면도[F3]/아이소[F4]/1인칭[F5])가 리본 뷰 메뉴 SSOT(정면/뒤/왼쪽/오른쪽/위/아래/등각)와 명칭·구성 불일치 + 위(Top) 누락 + 잘못된 F-key 라벨.
fix: 컨텍스트 메뉴를 리본 뷰 메뉴 7방향(QA-014 fix)과 정합. 정면/뒤/왼쪽/오른쪽/위/아래/등각 + 1인칭. 명칭 통일 + 위(Top) 추가 + 잘못된 F-key 라벨 제거(단축키 체계 QA-030 유동이라 hint 제거). GetCamCtrl()은 QA-014 캐시 controller 반환 → 실 동작.
검증
• 컴파일 + 캡처 회귀. 컨텍스트 메뉴 클릭 실 동작은 Stage 2 사용자 PC(우클릭).
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — 씬 컨텍스트 메뉴 뷰 서브메뉴 항목 리본 정합

v0.1.501 — v0.1.501 — QA-106 Inspector 텍스트 입력 clobber 추가 가드 (값-변경 re-render skip)

v0.1.501 v0.1.501 — QA-106 Inspector 텍스트 입력 clobber 추가 가드 (값-변경 re-render skip) zip release notes GitHub
핵심 변경
QA-106 (Inspector 텍스트필드 키 입력 불가 + 클릭 시 초기화 — 재탈락): v0.1.245~412 가드(주기 refresh skip + 5s grace + root callbacks)에도 잔존. root cause = 값-변경 re-render(센서/액추에이터/타워램프 카드 재구성)가 텍스트 입력 편집 중 발화 → 입력 필드 destroy.
추가 가드: IsInspectorTextInputFocused() 신규 — _detailPane 안 TextField/FloatField/IntegerField/DoubleField focus 검출. 5개 값-변경 re-render 호출처에 가드 추가 → 텍스트 입력 편집 중 re-render skip(모델은 갱신, 시각 rebuild만 blur 후 지연). 토글/드롭다운/선택변경은 텍스트필드 미focus라 정상 렌더.
검증
• 컴파일 + 캡처 회귀. 실 입력(필드 타이핑 중 값 유지)은 Stage 2 사용자 PC 의무.
• 4회 재탈락 이력 — 본 가드는 additive(working 동작 불변). 잔존 시 Stage 2 진단 로그 추가 검토.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — IsInspectorTextInputFocused 헬퍼 + 값-변경 re-render 5곳 가드

v0.1.500 — v0.1.500 — QA-135 프로젝트 로드 후 전체 흰색 REAL FIX (Simple Lit fallback → Unlit 일치)

v0.1.500 v0.1.500 — QA-135 프로젝트 로드 후 전체 흰색 REAL FIX (Simple Lit fallback → Unlit 일치) zip release notes GitHub
핵심 변경
QA-135 (프로젝트 불러오기 후 전체 오브젝트 흰색 불투명 — v0.1.492 QC 신규): 부품은 로드되나 material 미복원, 전체 흰색.
root cause 확정 (spec-implementation-judgment — 코드 추적): 초기 로드(Bootstrap L274)는 Factory00MaterialGenerator(URP/Unlit, 조명 무관, glb baseColor 정확). 그러나 프로젝트 Open 재임포트(L3109)는 StepImportService.ImportGlbAsync → 내부 ApplyShaderFallback(URP/Simple Lit 교체). Simple Lit는 조명 반응 → 씬 조명 부재/오류 시 전체 흰색 over-render. QC 로그 [step-import] shader fallback 4371 mat 이 증거.
REAL FIX: ImportGlbAsyncuseMaterialGenerator 파라미터 추가. Open 재임포트는 true → 초기-로드와 동일한 Factory00MaterialGenerator(URP/Unlit) + Simple Lit fallback skip. STEP 메뉴 임포트는 default false 유지(Stage 2 검증된 동작 보존).
검증
• 컴파일 + 캡처 회귀. 로드 후 흰색 해소는 Stage 2 사용자 PC 의무(autoQA는 초기 씬만 캡처, Open 후 렌더 미검증). 초기-로드가 Unlit로 magenta 없이 작동하므로 동일 경로 = 안전 추정.
영향 파일
Assets/Scripts/Importers/StepImportService.cs — ImportGlbAsync useMaterialGenerator 파라미터 + ApplyShaderFallback 조건부 skip
Assets/Scripts/Game/Factory00Bootstrap.cs — Open 재임포트 useMaterialGenerator:true

v0.1.499 — v0.1.499 — QA-014 뷰 메뉴 카메라 프리셋 REAL FIX (GetCam null root cause)

v0.1.499 v0.1.499 — QA-014 뷰 메뉴 카메라 프리셋 REAL FIX (GetCam null root cause) zip release notes GitHub
핵심 변경
QA-014 (뷰(V) 메뉴 7종 클릭 무동작 — v0.1.492 QC 재탈락): F5~F8 단축키는 동작하나 메뉴 클릭은 무동작.
root cause 확정 (spec-implementation-judgment — 코드 추적): GetCam() = Camera.main.GetComponent(). 그러나 controller 는 별도 GameObject("CameraViewController", Bootstrap L401 신규 생성)에 부착 → Camera.main 에 없음 → GetCam() = null → 리본 뷰 메뉴 GetCam()?.ApplyMode no-op. F5~F8 은 controller 자체 Update 폴링이라 동작. GetCamCtrl()(컨텍스트 메뉴용)은 FindObjectOfType 라 정상 — 두 accessor 불일치가 증거.
REAL FIX: controller 를 _camCtrlRef 필드 캐시(find/create 직후 L406). GetCam() = 캐시 우선 + FindObjectOfType fallback. GetCamCtrl()GetCam() 통합(DRY 단일 소스).
검증
• 컴파일 + 캡처 회귀. 뷰 메뉴 7종(정면/뒤/왼쪽/오른쪽/위/아래/등각) 실 동작은 Stage 2 사용자 PC(마우스 클릭).
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — _camCtrlRef 필드 캐시 + GetCam/GetCamCtrl 통합

v0.1.498 — v0.1.498 — QA-103 M-01 후속: OS window X 버튼 종료 확인 (Application.wantsToQuit)

v0.1.498 v0.1.498 — QA-103 M-01 후속: OS window X 버튼 종료 확인 (Application.wantsToQuit) zip release notes GitHub
핵심 변경
M-01 X 버튼 처리 (critic 중대 #1 "1순위" 해소): v0.1.497 은 파일>종료 메뉴 경로만 미저장 확인 팝업 커버. 본 빌드 = OS window X 버튼(타이틀바 닫기) 종료도 Application.wantsToQuit 가로채기로 dirty 시 확인 팝업 + 종료 보류.
빌드 hang 방지 설계: _forceQuit 플래그 — AppQuitCommandEvent 구독자가 종료 직전 true 설정 → wantsToQuit 항상 통과. 메뉴 확정 종료·autoQA capture 종료 모두 이벤트 경유 → 통과 보장. X 버튼만 _forceQuit=false 로 dialog 발동 (OS close 는 이벤트 미경유). loop 차단(저장안함→AppQuitCommandEvent→_forceQuit=true→재종료 통과).
Editor 제외 (#if !UNITY_EDITOR): Editor play-mode-exit 충돌 회피. standalone 빌드만 X 버튼 가로채기. OnDestroy 에서 핸들러 해제.
안전성 (빌드 자체가 검증)
• autoQA capture: 씬 로드 → MarkSaved(clean) → 캡처 → AppQuitCommandEvent("capture-autoqa") → 구독자 _forceQuit=true → Application.Quit → wantsToQuit 통과 → 정상 종료. 본 빌드의 autoQA capture 정상 완료 = 안전장치 검증됨.
검증
• 컴파일 + autoQA capture 정상 종료(빌드 hang 0). X 버튼 실 동작(dirty 시 팝업)은 Stage 2 사용자 PC.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — _forceQuit 필드 + AppQuitCommandEvent 구독자 _forceQuit 설정 + wantsToQuit 등록/OnWantsToQuit/OnDestroy 해제

v0.1.497 — v0.1.497 — QA-103 M-01 종료 시 미저장 변경 확인 팝업 (Windows 표준)

v0.1.497 v0.1.497 — QA-103 M-01 종료 시 미저장 변경 확인 팝업 (Windows 표준) zip release notes GitHub
핵심 변경
QA-103 M-01 (종료 시 미저장 변경 확인): 직전까지 파일>종료 메뉴 → 경고 없이 즉시 종료(데이터 손실 위험). Windows 표준 확인 팝업 구현.
dirty 추적 (UndoStack): IsDirty = 저장 시점 top 커맨드 vs 현재 top 참조 비교. undo로 저장 시점까지 되돌리면 자동 clean. 저장/신규/로드 시 MarkSaved() 호출.
확인 팝업 (3버튼): "저장 후 종료 / 저장 안 함 / 취소". full-screen 모달 backdrop + 다크 테마. ESC/backdrop 클릭 = 취소.
SaveCurrentProject(bool):bool 추출 (DRY): 옛 cmd-save 클로저를 메서드화 → cmd-save / cmd-save-as / 종료팝업 "저장 후 종료" 공유.
critic 결과 (CONDITIONAL → 치명 해소)
치명 1 → 해소: "저장 후 종료" close() 선행 → Save As 취소 시 팝업 유실 → 저장 성공 시에만 close+quit, 취소/실패 시 팝업 유지(Windows 표준).
중대 (재분류·처리): ESC cascade 충돌 → ESC를 Bootstrap.Update polling + 다이얼로그 가드로 통일(해소) / MouseDownEvent → PointerDownEvent(해소) / 트림 후 false dirty = 100+ 편집 edge, 데이터 손실 아닌 보수적 경고(v1 수용).
deferred (follow-up): OS window X 버튼(Application.wantsToQuit) 미처리 — 이유: wantsToQuit가 dirty 시 autoQA capture 빌드 종료를 차단 → 빌드 hang 위험 + Stage 2 검증 불가. 안전을 위해 별도 사이클(BUG/SPEC 명시) 예약. 현재 = 파일>종료 메뉴 경로만 커버.
v1 scope: 비-커맨드 편집(슬라이더 드래그 등 UndoStack 미경유)은 dirty 미반영 — 대부분 의미있는 편집은 커맨드 경유. 향후 보완 가능.
• 판정: 치명 0 / 실 중대 0 → PASS (X버튼·edge는 follow-up 명시).
검증
• 컴파일 + 캡처 회귀. 팝업 실 동작(파일>종료 → dirty 시 팝업 → 저장/취소)은 Stage 2 사용자 PC(마우스 클릭).
영향 파일
Assets/Scripts/Game/UndoStack.cs — IsDirty/MarkSaved/_cleanMarker + Clear 리셋
Assets/Scripts/Game/Factory00Bootstrap.cs — RequestQuit/ShowQuitConfirmDialog/CloseQuitDialog + SaveCurrentProject 추출 + MarkSaved 3곳 + cmd-quit 배선 + ESC cascade 가드

v0.1.496 — v0.1.496 — QA-102 B-02 최근 프로젝트 ▶ 하위메뉴 affordance + QA-103 M-items 코드 검증

v0.1.496 v0.1.496 — QA-102 B-02 최근 프로젝트 ▶ 하위메뉴 affordance + QA-103 M-items 코드 검증 zip release notes GitHub
핵심 변경
QA-102 B-02 (최근 프로젝트 ▶ 하위메뉴): 기능은 v0.1.226 부터 이미 구현됨 — "최근 프로젝트(R)" 클릭 시 ContextMenuElement 하위메뉴가 버튼 아래 표시(최근 파일 최대 5개, 각 클릭으로 열기). gap = ▶ 시각 인디케이터 부재 → Ribbon.uxml 라벨에 ▶ 추가(앱 내 트리 ▶/▼ affordance 정합, 우측 정렬). 재구현 아닌 affordance polish.
QA-103 M-items 코드 검증 (룰 spec-implementation-judgment — 재구현 전 코드 우선 검토)
PM 추적은 v0.1.366 기반 stale. 현재 코드 검증 결과 대부분 이미 구현:
M-02 뷰 모드: CameraViewMode F1~F4(기본/평면/측면/아이소) + 1인칭 = wired. 종결 가능.
M-05 신호 시뮬: SignalSimulatorPanel (v0.1.182, 협업자 spec signal-simulator §6) = wired. 종결 가능.
M-06 통신 설정: 실행 메뉴에 통신설정 흡수(Communication 폐지) = wired. 종결 가능.
M-09 1인칭 모드: OnEnterFirstPerson + WASD/마우스 시선/QE 상하/Esc 종료 = wired. (F10 바인딩 여부 PM 재확인)
M-01 종료 팝업: AppQuitCommandEvent(v0.1.297) 이벤트 스캐폴딩 존재하나 미저장 변경 확인 팝업은 미구현(LNB P1 진입 시 추가 예정). 부분 — 신규 기능 영역(사용자/PM 명시 필요).
검증
• 컴파일 + 캡처 회귀 확인. ▶ 표시·하위메뉴 실 동작은 Stage 2 사용자 PC(마우스 클릭).
영향 파일
Assets/UI/Components/Ribbon.uxml — cmd-recent 라벨 ▶ 인디케이터 추가

v0.1.495 — v0.1.495 — QA-102 B-01 Alt+글자 mnemonic 메뉴 진입 REAL FIX (무동작 path 교체)

v0.1.495 v0.1.495 — QA-102 B-01 Alt+글자 mnemonic 메뉴 진입 REAL FIX (무동작 path 교체) zip release notes GitHub
핵심 변경
QA-102 B-01 (Alt+글자 mnemonic 메뉴 진입, Windows 표준): 매핑은 v0.1.402 부터 7개 전부 존재(Alt+F=파일/E=편집/V=뷰/C=부품·컴포넌트/R=실행/T=도구/H=도움말)했으나, 클릭 트리거가 NavigationSubmitEvent.SendEvent무동작(focus-tab-navigation cap 학습: UI Toolkit Navigation*Event SendEvent 실효 X).
REAL FIX: 검증된 직접 호출 ShowLnbDropdown(idx) + _lnbTabs[idx].Focus() 로 전환 (Alt-단독 활성화·키보드 메뉴 순회가 쓰는 동일 path). idx = kRibbonTabs 순서. rootEl.Q
중복 방지: Alt+글자 발화 시 _altOtherKey=true(기존 anyKeyDown detect)로 Alt-단독 메뉴바 활성화 차단됨. 단일 키 T/H 핸들러는 이미 Alt 가드 보유, F/E/V/R/C 충돌 없음.
판단 (룰 spec-implementation-judgment + focus-tab-navigation 학습)
• spec WHAT(Alt+글자 → 해당 메뉴) 충족 + HOW 는 코드 검증된 ShowLnbDropdown path 채택 (옛 NavigationSubmitEvent 는 UI Toolkit 무동작 확정).
• B-01 = 직전 "partial" 의 정체 = 매핑 존재하나 트리거 무동작. 신규 코드 아닌 트리거 교체.
검증
• 컴파일 + 캡처 회귀 확인. Alt+글자 실 동작은 Stage 2 사용자 PC 의무 (Alt = WM_SYSKEYDOWN 모디파이어 자동화 한계, 자동화 6-path 학습).
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — Alt+mnemonic 블록 NavigationSubmitEvent → ShowLnbDropdown 직접 호출 전환

v0.1.494 — v0.1.494 — QA-102 B-03 후속: 컴포넌트 삭제 Undo + ComponentEditCommand 일반화

v0.1.494 v0.1.494 — QA-102 B-03 후속: 컴포넌트 삭제 Undo + ComponentEditCommand 일반화 zip release notes GitHub
핵심 변경
QA-102 B-03 후속 (직전 critic 중대 — 추가만 Undo 가능, 삭제 비대칭): 컴포넌트 삭제(Ctrl+Z 복원) 가능화.
ComponentEditCommand 일반화 (옛 AddComponentCommand): do/undo 페어 액션을 받는 단일 커맨드로 일반화 (DRY). 추가 = do:add/undo:remove, 삭제 = do:remove/undo:동일 인스턴스 복원.
6개 Remove 헬퍼 Undo wrap: ServoAxis/Pneumatic/RotaryPneumatic/RotaryActuator/PhotoSensor/TowerLamp. Remove 는 컴포넌트 인스턴스를 받아 driver unregister + 리스트 제거만 하므로, closure 가 동일 인스턴스 보존 → undo 시 설정값(SensingDistance/ModbusCoil/ContactType 등) 그대로 복원 (데이터 손실 0).
TowerLamp Add 도 wrap (직전 미wrap, 비대칭 해소) + EmissionDriver material lifecycle 처리: 신규 ReapplyLamp(id) => ApplyEmission(id) — 삭제 undo(또는 add redo) 시 lamp 재추가 후 material 강제 재생성 (InvalidateLamp 역연산). static ON lamp 도 즉시 복원 (update 루프는 blink 만 처리).
critic 결과 (CONDITIONAL → 치명 해소)
치명 1 → 해소: ComponentEditCommand.Undo 가 _suppressAddRebuild 가드 우회(inline Rebuild) → Undo 도 Refresh() 경유로 통일 (가드 일관 적용 + DRY).
중대 (재분류): (a) re-add 상호배제 가드 우회 = 비결함 (UndoStack LIFO 순서가 "서보 Remove→회전 Add→서보 undo" 시나리오 차단 — 회전 Add 가 먼저 undo됨). (b) Pneumatic visualizer GC churn = register/unregister 정확한 lifecycle, leak 없음, v0.1.491 Add undo 와 동일 = 중간 등급. (c) TowerLamp null 드라이버 = 방어적 edge(런타임 미발생), 데이터 복원 정상.
• 판정: 치명 0 / 실 중대 0 → PASS.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — ComponentEditCommand 일반화(Undo→Refresh DRY) + 6 Add rename + 6 Remove wrap + TowerLamp Add wrap
Assets/Scripts/Outputs/TowerLampEmissionDriver.cs — public ReapplyLamp(string) 신규

v0.1.493 — v0.1.493 — QA-126 R-7 PhotoSensor Raw 감지 이벤트 분리 (딜레이 무관 즉시 발화)

v0.1.493 v0.1.493 — QA-126 R-7 PhotoSensor Raw 감지 이벤트 분리 (딜레이 무관 즉시 발화) zip release notes GitHub
핵심 변경
QA-126 R-7 (OnDelay/OffDelay가 씬 이벤트까지 지연): JP 명시 "딜레이는 센서 출력 변경만 지연시키고, 씬에서 오브젝트를 검출한 이벤트는 딜레이와 무관하게 즉시 발생해야 함." 기존 코드는 raw 감지 → 딜레이 게이트 → FinalOutput → SensorStateChangedEvent 단일 사슬이라 씬 검출 이벤트 자체가 딜레이됨.
fix = 이벤트 2단계 분리 (S0005 summary r004 §8):
SensorDetectedEvent 신규 — Raw 감지 edge 변화 시 딜레이 무관 즉시 발행. 씬 시각화·인디케이터·디버그 구독용.
SensorStateChangedEvent 유지 — FinalOutput edge(딜레이+ContactType 반영 후). PLC 출력용.
PhotoSensorComponent.UpdateSensor: raw 감지 확정 직후(딜레이 블록 앞) _lastPublishedRaw edge 비교로 즉시 발행. 초기 raw=false 정합으로 시작 spurious 이벤트 없음.
협업자 spec 정합 (룰 spec-implementation-judgment)
• S0005 summary r005 §8 이벤트 목록 + §11 결정 이력 + 위임 브리프 확정 사양 채택.
• QC 체크리스트 r155 "§7 확정 대기" 표기는 stale — 실제 summary는 이벤트 목록을 §8에 확정(§7=시각화 명세). summary SSOT 직접 검증으로 확정 확인.
• 타임스탬프 필드명: spec 원문 Timestamp 대신 코드베이스 형제 이벤트(SensorStateChangedEvent) 컨벤션 TimestampSec 채택(내부 일관성 우선). 구독 코드는 factory00 내부 작성이므로 영향 없음.
• 구독자 미배선: R-7 위임 브리프는 이벤트 발행 분리만 요구. 씬 시각화·인디케이터 구독자 배선은 PM 명시 시 후속.
검증
• critic PASS (치명 0 / 중대 0). SoC(UpdateSensor 전용, ContactType 토글 시 미발화) + 생명주기(EventBus.Reset null) + 회귀(SensorPlcBridge 무관) 모두 정합.
영향 파일
Assets/Scripts/Events/SensorDetectedEvent.cs — 신규 이벤트 struct (SensorId/PartId/RawValue/TimestampSec)
Assets/Scripts/Events/EventBus.cs — OnSensorDetected event + Publish overload + Reset null
Assets/Scripts/Sensors/PhotoSensorComponent.cs_lastPublishedRaw 필드 + Initialize + UpdateSensor 즉시 발행
Assets/Scripts/Sensors/ISensor.cs — doc 주석 (이벤트 2종 분리 명시)

v0.1.492 — v0.1.492 — QA-102 B-05 Delete 후 씬 클릭 불가 fix + QA-102 기해결 검증(B-04/B-06/M-07/M-08)

v0.1.492 v0.1.492 — QA-102 B-05 Delete 후 씬 클릭 불가 fix + QA-102 기해결 검증(B-04/B-06/M-07/M-08) zip release notes GitHub
핵심 변경
B-05 (Delete 후 씬 오브젝트 선택 불가, 간헐): root cause = DeleteSelectedPart 가 3D click handler drag-state(_isDragSelecting/_lmbDownPos/_lmbDownFrame/_inspectorDragLock)를 reset 안 함. Cut(CutSelected)은 v0.1.416 에서 자체 reset 하나 직접 Delete(키/버튼) 경로는 누락. fix = DeleteSelectedPart 에 동일 reset 추가 (Cut/Delete 정합).
QA-102/103 코드 검증 (룰 spec-implementation-judgment — 재구현 전 코드 우선 검토)
B-04 (Ctrl+X 후 씬 클릭 불가): 이미 fix됨 (v0.1.416 CutSelected drag-state reset). PM v0.1.366 보고 stale → 종결 가능.
B-06 (전체보기/카메라 프리셋): 카메라 프리셋 v0.1.489 + Zoom Fit 기wired → 종결 가능.
M-07/M-08 (도구 측정/충돌/스크린샷/시나리오): 현재 코드 이미 wired (clicked 바인딩 존재) → 종결 가능.
잔여(별도 사이클): B-01(Alt mnemonic 전체 — 부분만 존재) / B-02(Recent ▶ 하위메뉴) / B-08(Inspector 우측 분리, 대형) / M-01~06/09~11(신규 기능) / B-03 후속(Remove Undo·TowerLamp).
검증
• 빌드 컴파일 + 사용자/PM QC: Delete 후 씬 다른 오브젝트 클릭 정상.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — DeleteSelectedPart drag-state reset.

v0.1.491 — v0.1.491 — QA-102 B-03 컴포넌트 추가 Ctrl+Z Undo 등록 (5 컴포넌트 + redo/NRE 가드)

v0.1.491 v0.1.491 — QA-102 B-03 컴포넌트 추가 Ctrl+Z Undo 등록 (5 컴포넌트 + redo/NRE 가드) zip release notes GitHub
핵심 변경
B-03 (컴포넌트 추가 후 Ctrl+Z 무동작): root cause = Add 헬퍼(센서/구동부)가 list.Add + driver.Register 직접 호출 → _undoStack 미경유. fix = 신규 AddComponentCommand : IEditCommand (Execute=add+UI갱신, Undo=remove+UI갱신) + 5개 Add 헬퍼(PhotoSensor/ServoAxis/Pneumatic/RotaryActuator/RotaryPneumatic) _undoStack.ExecuteAndPush 경유. Delete/Duplicate/Cut/Gizmo 패턴 미러.
critic FAIL → 치명 2건 해소
치명 #1 (redo 중복 등록): ActuatorDriver.RegisterActuator / SensorPollingDriver.RegisterSensor_actuators/_sensors.Add 무방어 → if (Contains) return; dup 가드 추가 (Undo/Redo 재등록 시 2배 발화/유령 차단).
치명 #2 (stale Part NRE): Part 삭제 후 Add-undo 역전 시 _part.cachedTransform 파괴 → RenderInspector NRE. _part.cachedTransform != null Unity-null 가드 추가.
범위 외 (B-03 후속 큐)
• 중대: Remove 헬퍼 3종 Undo 미지원 (Add↔Remove 비대칭) / TowerLamp Add Undo 미래핑 → 별도 사이클.
• 다중선택 Add = 부품마다 별도 Undo 커맨드 (Ctrl+Z M회) — batch 는 후속.
검증
• 빌드 컴파일 + 사용자 PC: 컴포넌트 추가 → Ctrl+Z 복원 / Ctrl+Y 재추가 (2배 속도/유령 無).
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — AddComponentCommand + 5 헬퍼 wrap.
Assets/Scripts/Actuators/ActuatorDriver.cs · Assets/Scripts/Sensors/SensorPollingDriver.cs — dup 가드.

v0.1.490 — v0.1.490 — QA-102 B-07 도구 '부품이동' 항목 제거 + QA-102/103 검증 (M-07/M-08/B-06 기해결 확인)

v0.1.490 v0.1.490 — QA-102 B-07 도구 '부품이동' 항목 제거 + QA-102/103 검증 (M-07/M-08/B-06 기해결 확인) zip release notes GitHub
핵심 변경
B-07 (도구 '부품이동' 제거): Q-5 폐기 확정 (Gizmo 씬 클릭 조작으로 커버, 2026-05-23 JP). Ribbon.uxml tool-move-part 버튼 + 코드 BindRibbonCommandPlaceholder 양쪽 제거 (deprecated-spec-marking 룰 정합).
QA-102/103 코드 검증 (룰 spec-implementation-judgment + handoff-verify-before-report — 재구현 전 코드 상태 확인)
M-07 (도구 길이/각도/충돌 측정): 현재 코드 이미 wiredreview-measure(측정 로직, v0.1.346) / review-angle(L2526) / review-collision(L2556) cmds-tools 버튼에 clicked 바인딩 존재, 중복 0. PM v0.1.366 보고 stale → 종결 가능.
M-08 (도구 스크린샷/시나리오): 이미 wiredpresent-screenshot(ScreenCapture) / present-scenario-play(RunInterfaceEmulationDemo) 바인딩 존재. 종결 가능.
B-06 (카메라 프리셋 + 전체보기): 카메라 프리셋 v0.1.489 fix 완료 / Zoom Fit(view-fit) 기wired. 종결 가능.
검증
• 빌드 컴파일 + UXML 검증. 도구 메뉴에 '부품이동' 항목 없음 / 측정·스크린샷·시나리오 항목 동작은 PM QC.
영향 파일
Assets/UI/Components/Ribbon.uxml — tool-move-part 버튼 제거.
Assets/Scripts/Game/Factory00Bootstrap.cs — tool-move-part placeholder bind 제거.

v0.1.489 — v0.1.489 — 뷰 메뉴 카메라 프리셋 무동작 fix (QA-014/B-06, F5~F8 ApplyMode 맵핑)

v0.1.489 v0.1.489 — 뷰 메뉴 카메라 프리셋 무동작 fix (QA-014/B-06, F5~F8 ApplyMode 맵핑) zip release notes GitHub
핵심 변경 (사용자 v0.1.487 PC 보고)
증상: 뷰(V) 메뉴 정면/뒤/왼쪽/오른쪽/위/아래/등각 클릭해도 카메라 무동작. F5~F8(펑션 567)은 정상 동작.
root cause: 뷰 메뉴 항목이 SetPresetView(yaw,pitch) 호출 — 내부에서 _orbitYawPitch 설정 후 ApplyMode(CameraViewMode.Default)(perspective)로 우회 → 프리셋 무동작 (QA-014 v0.1.391~413 반복 실패). F5~F8 은 ApplyMode(CameraViewMode.Front/Right/Top/Iso) 직접 호출 → 동작.
fix (사용자 제안 "같은 기능 버튼 맵핑"): 뷰 메뉴 7항목을 검증된 ApplyMode(CameraViewMode.X) 직접 호출로 전환. enum 에 Back/Left/Bottom 신설 + ApplyMode case 추가 (Front/Right 패턴 미러: orthographic + 각도 + ApplyPresetCameraPosition). 각도: Front yaw0 / Back yaw180 / Left yaw-90 / Right yaw90 / Top pitch89 / Bottom pitch-89 / Iso yaw45 pitch35.264.
검증
• 빌드 컴파일 검증. 사용자 PC: 뷰 메뉴 7방향 클릭 = F5~F8 과 동일하게 카메라 전환.
영향 파일
Assets/Scripts/Game/CameraViewController.cs — enum Back/Left/Bottom + ApplyMode 3 case.
Assets/Scripts/Game/Factory00Bootstrap.cs — 뷰 메뉴 7항목 SetPresetView → ApplyMode.

v0.1.488 — v0.1.488 — Tab 이중 이동 + 3D D키 포커스 이동 fix + 포커스 시각 경량화 (사용자 PC 보고)

v0.1.488 v0.1.488 — Tab 이중 이동 + 3D D키 포커스 이동 fix + 포커스 시각 경량화 (사용자 PC 보고) zip release notes GitHub
핵심 변경 (사용자 v0.1.487 PC 테스트 보고 3건)
Tab 1회에 포커스 2칸 이동: UI Toolkit 네이티브 NavigationMoveEvent(Tab) + Bootstrap.Update Input.GetKeyDown(Tab) 이중 mover. v0.1.482 가 outline-0 회피 위해 Next/Previous 통과시킨 게 원인.
3D viewport 포커스 시 D키 → 파일 메뉴 이동 + 카메라 안 됨: W/A/S/D 도 NavigationMoveEvent 로 변환되어 focus 이동 (사용자 추측 정확).
fix A: NavigationMoveEvent 콜백에서 Next/Previous 통과 제거 → 전부 차단. Tab 단일 mover = Update 핸들러(custom 필터링/순서 보존), WASD = 카메라 전용. outline-0 실제 root cause 는 focus-dummy 중복(QA-124)이고 v0.1.485 if (_focusDummy==null) 가드로 이미 fix → 본 차단으로 회귀 안 함 예상.
fix B (포커스 시각 경량화): 사용자 명시 "리스트 포커스 시 전체 노란 fill 불필요, 얇은 아웃라인만 (Windows 표준)". FocusIn 3px gold + soft 배경 → 1px 테두리만 + fill 제거. (UI Toolkit 런타임 dotted border 미지원 → 1px solid 대체.)
검증
• 빌드 컴파일 검증. 사용자 PC 라이브 테스트: Tab 1칸 이동 / 3D D키 = 카메라 이동(포커스 이동 X) / 리스트 포커스 = 얇은 아웃라인.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — NavigationMoveEvent 전체 차단 + FocusIn 1px no-fill.

v0.1.487 — v0.1.487 — QA-119 빈 씬 Open 시 부품 0 복원 회귀 fix (GLB 기반 프로젝트 재임포트 fallback)

v0.1.487 v0.1.487 — QA-119 빈 씬 Open 시 부품 0 복원 회귀 fix (GLB 기반 프로젝트 재임포트 fallback) zip release notes GitHub
핵심 변경
QA-119 root cause 확정: .twn 스키마에 stepSourcePath만 있고 glb 경로 없음. Save 는 _lastStepPath(STEP 임포트 시만 설정)만 저장 → 기본 factory 씬(번들 glb 기반, STEP 임포트 안 함)은 stepSourcePath="" → Open 시 needAutoImport=false → 재임포트 안 됨 → 빈 씬 → [file-open] applied 0/8763 parts. PM repro "factory00-project.twn" 이 정확히 이 케이스.
fix (v0.1.487): OpenTwnPath 자동 재임포트 조건 확장 — stepSourcePath 비었으면 ResolveGlbPath()(기본 번들 glb) 직접 재임포트 fallback (STEP 변환 skip). 기존 index-order id remap + ApplyTwnPayload 재사용. STEP 기반 프로젝트는 기존 경로 유지.
검증
• 빌드 컴파일 검증. PM QC / Stage 2 의무: 예시 3(빈 씬 → factory00-project.twn Open → 8763 부품 + 속성 복원) + 예시 2(부품 삭제 후 Open → 재생성) round-trip.
• 한계: 커스텀 glb(기본 외) 기반 프로젝트는 glbSourcePath 스키마 부재로 기본 glb 재임포트 → 기하 불일치 가능. 기본 factory 씬(PM repro)은 정합. 커스텀 glb 대응 = glbSourcePath 스키마 추가(별도 사이클).
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — OpenTwnPath 재임포트 조건 + glb fallback.

v0.1.486 — v0.1.486 — QA-126 잔여 R-3 (회전 드래그 scrub) + R-5 (감지 영역 cone 정합)

v0.1.486 v0.1.486 — QA-126 잔여 R-3 (회전 드래그 scrub) + R-5 (감지 영역 cone 정합) zip release notes GitHub
핵심 변경
R-3 (LocalRotation 마우스 드래그 scrub): SensorVec3Field(PhotoSensor 카드 위치/회전)가 scrub 없는 Vector3FieldElement(AxisFieldElement = 키인 only) 대신 3개 AxisFieldScrubElement(드래그 scrub) 사용 — Inspector P3 EditableVec3Row 패턴 미러. 위치/회전 모두 드래그 scrub 활성화.
R-5 (감지 영역 ≠ 시각 영역): 감지가 col.bounds.center 각도만 봐서 큰 오브젝트 edge 가 cone 안이어도 center 가 축에 와야 감지. center 체크 보존 + collider AABB closest-point 체크 추가(OR) — object edge 가 cone 닿으면 감지. axisProj>0 가드로 전면 반구만 (뒤쪽 over-detection 차단, 직접반사형 spec 정합).
검증
• critic CONDITIONAL → 중대 #3(뒤쪽 over-detection) axisProj>0 가드로 해소. 중대 #1(working struct) = RenderInspector 카드 재생성으로 비결함(P3 패턴 동일). 치명 0.
• 모두 마우스/시각 구동 — Stage 2 사용자 PC + PM QC 검증 의무 (회전 필드 드래그 scrub / 부채꼴 전체 감지).
QA-126 잔여
R-7 (OnDelay/OffDelay 씬 이벤트 분리): PM r138 사양 변경 동반 (Raw 감지 이벤트 별도 발화 spec 확정 대기 — spec-vs-codebase 사전검토 필요) → 별도 사이클.
• R-4 (IsVisualized): 코드 버그 아님 — PM 재확인 요청 게시 (v0.1.484 handoff).
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — SensorVec3Field AxisFieldScrubElement 전환.
Assets/Scripts/Sensors/PhotoSensorComponent.cs — UpdateSensor closest-point 감지.

v0.1.485 — v0.1.485 — QA-124 focus-dummy 중복 root cause fix + QA-130 Alt 진단 로그 (focus 클러스터)

v0.1.485 v0.1.485 — QA-124 focus-dummy 중복 root cause fix + QA-130 Alt 진단 로그 (focus 클러스터) zip release notes GitHub
핵심 변경
QA-124 root cause fix (22빌드 미해소): focus-dummy/viewport-focus-anchor 생성 + FocusIn/Out 콜백 등록이 ForceLayoutStyles(L1573+L4885 다회 호출) 내부에 가드 없이 있어 매 호출마다 신규 생성 + root.Add → child[6]/[7] NaN 중복 + 콜백 누적. if (_focusDummy == null) 가드로 1회만 생성 (바로 아래 settings-VM idempotent 가드 패턴 미러).
QA-130 진단 로그 (PM r152 QA-134 명시 요청): Alt detect path 에 [alt] downTime set / [alt] otherKey=true / [alt] lnbTabs[0].Focus() 호출 3종 + [focus-dummy] 1회 생성 가드 통과 로그 추가. 다음 QC 에서 WASD 기동 시 [alt] lnbTabs[0].Focus() 발화 여부로 Alt 회기 확정.
클러스터 효과 (QA-123/124/130)
• QA-124 중복 제거 = QA-130(Alt false trigger 매개 가설 D) + QA-123(focus-dummy NaN 중복 매개) 공유 root cause 해소 가능.
• QA-130 순수 Alt 코드 회기 여부는 진단 로그로 다음 QC 확정 (순수 WASD 로는 _altDownTime=-1 stale 가드라 Alt-up 분기 미발화 분석 — 중복이 매개 가능성 우선).
검증
• 진단 로그는 임시 — 58th seal 시 제거 의무 (no-keyboard-sequence-in-build.md / binary-search-code-tracking.md 정합).
• 가드 brace 균형 확인. PM 자체 QC + Player.log [alt]/[focus-dummy] 로그 분석으로 root cause 확정.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — focus-dummy 가드 (L4045) + Alt 진단 로그 3종.

v0.1.484 — v0.1.484 — QA-126 PhotoSensor spot-check fix 3건 (R-1 중복차단 / R-2 거리 편집 / R-6 NO·NC 즉시 갱신)

v0.1.484 v0.1.484 — QA-126 PhotoSensor spot-check fix 3건 (R-1 중복차단 / R-2 거리 편집 / R-6 NO·NC 즉시 갱신) zip release notes GitHub
핵심 변경
R-1 (센서 중복 부착 차단): AddPhotoSensorToPartCount >= 1 가드 추가 (구동부/타워램프 패턴 정합). Inspector "+ 센서 추가" 직접 호출 경로까지 차단. spec §3 단일 부착.
R-2 (SensingDistance 숫자 필드 편집): SensorSliderRoweditable 파라미터 추가 → SensingDistance만 read-only Label → 양방향 FloatField(slider↔field 동기 + min/max clamp + SetValueWithoutNotify 루프 차단). 나머지 8개 슬라이더는 기존 유지.
R-6 (NO/NC 변경 시 출력 즉시 갱신): PhotoSensorComponent FinalOutput 계산을 RecomputeFinalOutput()(internal)로 추출. ContactType 토글 시 즉시 재계산 + Inspector 재렌더(Button.clicked dispatch 완료 후 schedule.Execute defer — orphan 위험 차단).
검증
• critic 코드리뷰 CONDITIONAL → 중대 1건(Button.clicked 안 RenderInspector orphan) schedule.Execute defer로 해소 + RecomputeFinalOutput internal 강등. 치명 0.
• 모두 마우스/Inspector 구동 — Stage 2 사용자 PC 검증 의무 (중복 차단 토스트 / 거리 필드 키인 / NO·NC 출력 즉시 갱신).
QA-126 잔여 (별도 사이클)
R-3 LocalRotation Vector3FieldElement scrub 마이그레이션 (~30줄).
R-4 IsVisualized: 코드 버그 아님 추정 — PhotoSensorVisualizer.Update가 매 프레임 IsVisualized || ownerSelected 평가. 선택 중 ray 유지는 spec §7 정합. PM 명확화 요청 (선택 해제 후 재확인).
R-5 감지 영역: 이미 OverlapSphere+각도지만 bounds.center 기준 → cone edge 미감지. closest-point geometry 수정 (moderate).
R-7 OnDelay/OffDelay 씬 이벤트 분리 (PM r138 사양 확정 대기).
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — R-1 가드 / R-2 editable / R-6 토글 defer.
Assets/Scripts/Sensors/PhotoSensorComponent.cs — R-6 RecomputeFinalOutput 추출.

v0.1.483 — v0.1.483 — QA-127 컴포넌트 Add 응답없음 + 센서 마구 추가 root cause fix

v0.1.483 v0.1.483 — QA-127 컴포넌트 Add 응답없음 + 센서 마구 추가 root cause fix zip release notes GitHub
핵심 변경
• root cause: RebuildVisibleParts 가 모든 부품마다 IsPartVisible 호출 + IsPartVisible 이 조상 체인마다 전체 Parts 선형 스캔 → O(N²×depth). 8763 부품 씬에서 컴포넌트 Add 직후 다초 freeze → OS 클릭 큐잉 풀림 → 엉뚱한 오브젝트에 센서 마구 추가(stray attach). freeze 가 두 증상의 공통 원인.
Fix1 (핵심): parentId→Part O(1) 사전 _partById 신설 → IsPartVisible / EnsureVisibleAncestors / GetPart 의 Parts 선형 스캔 제거. RebuildVisibleParts O(N²×depth) → O(N×depth) (약 4자릿수 단축). freeze 소멸 → 큐잉/stray attach 동시 해소.
Fix2: 다중 선택 Add 시 부품마다 rebuild 하지 않고 루프 종료 후 1회만 rebuild (_suppressAddRebuild). 6개 Add 핸들러 일관.
Fix3: 같은 Add 버튼 120ms 내 burst 클릭 차단 (방어선 — OS 큐잉 flush 흡수, 정상 재클릭은 통과).
검증
• critic 2차 코드리뷰 PASS (치명 0 / 중대 0). 1차 CONDITIONAL 지적(GetPart SSOT·tower-lamp rebuild·디바운스 윈도우) 전부 해소.
• 컴포넌트 Add 는 마우스 구동 — 자동화 6-path 한계. Stage 2 사용자 PC 검증 의무 (대규모 씬 컴포넌트 Add 후 freeze·stray attach 소멸 확인).
• PM 후보 (B) Modbus 5초 hang: ModbusTcpAdapter.Connect 가 mock skeleton(IsConnected=true + 로그)이라 블로킹 아님 — Add freeze 원인 아님.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs_partById SSOT 사전 + Add rebuild coalesce + 디바운스 가드.

v0.1.482 — v0.1.482 — NavigationMoveEvent Tab/Shift+Tab 통과 fix (사용자 PC outline 0 root cause)

v0.1.482 v0.1.482 — NavigationMoveEvent Tab/Shift+Tab 통과 fix (사용자 PC outline 0 root cause) zip release notes GitHub
사용자 PC 보고 (2026-05-29)
• 7번째 메뉴 (도움말 H) 후 Tab → outline 사라짐
• 좌측 패널 Tab 100회+ outline 0
• 메뉴 재진입 불가 (Tab + 마우스 click 모두)
Root cause 추정
Bootstrap.cs L1544~1548 root.RegisterCallback 가 모든 NavigationMoveEvent PreventDefault + StopPropagation. UI Toolkit 6에서 Tab/Shift+Tab는 NavigationMoveEvent.Direction.Next/Previous 발화. 본 callback 안 Tab navigation 까지 차단 → UI Toolkit focus controller 내부 state 불일치 → Bootstrap.Update polling Focus() 호출과 race.
핵심 변경
• L1544 callback 안 direction == Next/Previous (Tab/Shift+Tab) 만 통과
• W/A/S/D / 화살표 (Up/Down/Left/Right) 만 차단 (옛 의도 유지 — 우클릭+WAS 시퀀스 안 리스트 selection 보호)
• v0.1.481 진단 로그 3건 cleanup (binary-search-code-tracking.md 정합 — grep 0건 확인)
영향 파일
• Bootstrap.cs L1544 NavigationMoveEvent callback — direction 조건 추가
• Bootstrap.cs L4239 / L4288 / L4046 진단 로그 3건 cleanup
사용자 PC 검증 부탁 (사용자 명시 시점)
빌드 zip 다운로드 + 실행 + Tab N회 누름 → 7번째 메뉴 후 좌측 패널 도달 outline 검증 의무

v0.1.481 — v0.1.481 — [focus-diag] 진단 로그 (사용자 PC outline 0 결함 추적)

v0.1.481 v0.1.481 — [focus-diag] 진단 로그 (사용자 PC outline 0 결함 추적) zip release notes GitHub
사용자 PC 보고 (2026-05-29)
• 7번째 메뉴 (도움말 H) 후 outline 사라짐
• 좌측 패널 Tab 100회+ outline 0
• 메뉴 재진입 불가 (Tab 누름 + 마우스 click 모두)
핵심 변경
• Bootstrap.Update Tab key detect 시점 Debug.Log 3종 추가
1. Tab GetKeyDown 시점: focused name + type + textFocused + uiDocNull
2. allFocusable.Count + curIdx + nextIdx + next.name + next.type
3. FocusInEvent 발화 시: name + type + display
• 사용자 자동 발화 X (사용자가 Tab 누름 시만 출력) — 룰 no-keyboard-sequence-in-build.md 정합
다음 사이클 cleanup 의무
binary-search-code-tracking.md 정합 — REAL FIX 시점 grep 전수 revert
영향 파일
• Bootstrap.cs L4239 Tab key detect block (2 Debug.Log)
• Bootstrap.cs L4040 FocusInEvent callback (1 Debug.Log)
사용자 PC 검증 부탁
빌드 zip 다운로드 + 실행 + Tab N회 누름 + Player.log 공유 (어시스턴트 root cause 분석 의무)

v0.1.480 — v0.1.480 — [focus-diag] 진단 로그 cleanup + 자동화 한계 확정 영구화

v0.1.480 v0.1.480 — [focus-diag] 진단 로그 cleanup + 자동화 한계 확정 영구화 zip release notes GitHub
핵심 변경
• Bootstrap.cs L4238 [focus-diag] Debug.Log 1줄 제거 (v0.1.479 임시 진단 cleanup)
• binary-search-code-tracking.md 정합 — REAL FIX 후 grep 0건 확인
자동화 한계 확정 (v0.1.479 [focus-diag] 분석 결과)
| path | Unity Input.GetKey detect |
|---|---|
| PostMessage WM_KEYDOWN/UP | 1건만 (frame=316) |
| PostMessage + SetForegroundWindow | 1건 |
| .NET SendKeys.SendWait + WScript.Shell | 0건 |
| AutoHotkey v2 Send "{Tab}" (SendInput) | 0건 |
= 본 환경 (헤드리스 + schtasks /it + Parsec VDD) 안 모든 키 자동화 path 한계 확정.
Stage 2 사용자 PC 의무 영역 (영구)
• Tab N+ navigation 시각 검증 (allFocusable 93)
• focus outline visible (gold 3px)
• Enter/방향키/ESC/Alt 단독 (FT-1~14)
• 마우스 click / drag / hover
다음 cap 후보 path (미시도)
• Unity Test Framework Play Mode batch (Editor 안 VisualElement.Focus() 직접)
• Sunshine 원격 + 사용자 PC 직접
• 사용자 PC 관리자 권한 AHK 설치 후 시도

v0.1.479 — v0.1.479 — [focus-diag] Tab 진단 로그 임시 (5-path FAIL root cause 추적)

v0.1.479 v0.1.479 — [focus-diag] Tab 진단 로그 임시 (5-path FAIL root cause 추적) zip release notes GitHub
핵심 변경
• Bootstrap.Update Input.GetKeyDown(Tab) detect 직후 Debug.Log 추가
• Tab GetKeyDown=true / frame / textFocused / uiDocNull 출력
• 5 path 자동화 FAIL root cause = polling 자체 불도달 vs 가드 차단 식별 목적
다음 사이클 cleanup 의무
binary-search-code-tracking.md 정합 — REAL FIX 시점 grep 전수 revert 의무
영향 파일
• Bootstrap.cs L4238 — Debug.Log 1줄 + 코멘트 3줄 추가
사용자 명시 정합
"빌드에 넣는거 말고 실사용시 켰을때 탭이 지멋대로 눌리는 건 제외시킨다"
→ 진단 로그 = 자동 발화 X. Tab 누름 시 Player.log 출력만. 사용자 실 사용 시 영향 0.

v0.1.478 — v0.1.478 — F8 sequence revert (사용자 명시 재발방지)

v0.1.478 v0.1.478 — F8 sequence revert (사용자 명시 재발방지) zip release notes GitHub
핵심 변경
• v0.1.473 F8 키 trigger → Bootstrap.Update 100회 Tab+capture sequence 코드 ~70라인 즉시 revert
• _focusSeqIdx / _focusSeqTimer / _focusSeqActive state 변수 3건 제거
• 잔존 코드 0건 grep 검증 완료
사용자 명시 정합
"빌드 코드에 키보드입력 넣지마라 이거 테스트할때 모르고하면 너무불편하다 + 재발방지"
룰 영구화
• 신규 .claude/rules/no-keyboard-sequence-in-build.md — 빌드 안 자동 sequence 영구 금지
.claude/rules/automation-multi-key-sequence-pattern.md deprecated 명시 (historical 보존)
영향 파일
• Bootstrap.cs ~70라인 + state 변수 3건 제거
권장 path
• 자동화 검증 = ps1 외부 단일 키 N회 schtasks /run 호출
• 어시스턴트 자체 한계 영역 = 사용자 PC Stage 2 검증 부탁
• 1회용 디버그 키 = 사용자 명시 시만 + 다음 사이클 제거 의무

v0.1.477 — v0.1.477 — SubWindow/Help/Mx button name audit 7건

v0.1.477 v0.1.477 — SubWindow/Help/Mx button name audit 7건 zip release notes GitHub
핵심 변경
• HelpOverlayElement closeBtn → help-overlay-close
• MitsubishiPlcDriverPanel 2 → mx-reconnect / mx-disconnect
• SignalSimulatorPanel refresh + closeBtn → signalsim-refresh / signalsim-popup-close
• ModbusAddressMappingPanel refresh → modbus-mapping-refresh
• ModbusTcpInspectorPanel 2 → modbus-tcp-reconnect / modbus-tcp-disconnect
사용자 명시 정합
"탭한번 스샷한번 전수검사" — 모든 button name 식별 명시 (Bootstrap 외 SubWindow audit)
영향 파일
• HelpOverlayElement.cs L69 — name 1줄
• MitsubishiPlcDriverPanel.cs L149/L155 — name × 2
• SignalSimulatorPanel.cs L153/L508 — name × 2
• ModbusAddressMappingPanel.cs L147 — name 1줄
• ModbusTcpInspectorPanel.cs L144/L150 — name × 2
잔존 영역 (v0.1.478+ audit 후보)
• ModbusAddressMappingPanel del + add (각 row별 dynamic — ID 매핑 필요)
• SignalSimulatorPanel nameBtn 4 (Sensor/Servo/Pneumatic/Rotary — popup wiring)
• ContextMenuElement row (dynamic menu item — name 필요 여부 결정 필요)

v0.1.476 — v0.1.476 — Inspector button name audit 11건 통합 fix

v0.1.476 v0.1.476 — Inspector button name audit 11건 통합 fix zip release notes GitHub
핵심 변경
• Pneumatic A/B/Stop 3 button name (pneumatic-cmd-a/b/stop)
• Photosensor NO/NC 2 button name (photosensor-contact-no/nc)
• Add button 5건 (photosensor-add / servo-add / pneumatic-add / driver-add-disabled / towerlamp-add)
• Delete button 6건 (photosensor-delete / towerlamp-delete / rotary-delete / servo-delete / pneumatic-delete / rotary-pneumatic-delete)
사용자 명시 정합
"탭한번 스샷한번 전수검사" — F8 sequence 안 element 식별 명시 의무
영향 파일
• Bootstrap.cs L6523 / L6585 (Photosensor) — name 부여
• Bootstrap.cs L6780~6789 (Photosensor NO/NC) — name 부여
• Bootstrap.cs L6966 / L6971 / L6982 (driver add) — name 부여
• Bootstrap.cs L7075 / L7133 (TowerLamp) — name 부여
• Bootstrap.cs L7371 (Rotary delete) — name 부여
• Bootstrap.cs L7465 (Servo delete) — name 부여
• Bootstrap.cs L7676 (Pneumatic delete) — name 부여
• Bootstrap.cs L7736~7738 (Pneumatic A/B/Stop) — name 부여
• Bootstrap.cs L7887 (RotaryPneumatic delete) — name 부여
검증 (v0.1.476 F8 sequence)
• 21~24 다음 빌드에 name 부여 detect 의무

v0.1.475 — v0.1.475 — Inspector 명령 4 Button name 부여 (Servo/Rotary)

v0.1.475 v0.1.475 — Inspector 명령 4 Button name 부여 (Servo/Rotary) zip release notes GitHub
핵심 변경
• Servo AddCmdBtn 4 button name = actuator-cmd-{backward|stop|forward|home}
• Rotary AddCmdBtn 4 button name = rotary-cmd-{backward|stop|forward|home}
• F8 sequence 안 element 식별 명확 (21~24 빈 name 영역 fix)
• 사용자 시각 검증 명시 (Servo Inspector 4 명령 button)
사용자 명시 정합
"탭한번 스샷한번 전수검사" — element 식별 명시 의무
F8 sequence v0.1.474 결과 21~24 name 빈 Button detect
영향 파일
• Bootstrap.cs L7397~7408 (Rotary) + L7512~7523 (Servo) — name 1줄 추가 × 2영역
검증 (v0.1.475 F8 sequence)
• 21~24 → actuator-cmd-backward/stop/forward/home 명시 detect 의무

v0.1.474 — v0.1.474 — Inspector AxisFieldScrubElement name 부여 (X/Y/Z)

v0.1.474 v0.1.474 — Inspector AxisFieldScrubElement name 부여 (X/Y/Z) zip release notes GitHub
핵심 변경
• AxisFieldScrubElement 3개 인스턴스 name 부여 (axis-x / axis-y / axis-z)
• F8 sequence 안 식별 + 사용자 시각 검증 용이
• v0.1.473 F8 100 capture sequence 시 96~99 element 이름 누락 발견 fix
사용자 명시 정합
"탭한번 스샷한번 이렇게 전수검사" — 각 element 식별 명시 의무
영향 파일
• Bootstrap.cs L6118 — name 1줄 추가
검증 (v0.1.474 F8 sequence)
• 96~99 → axis-x / axis-y / axis-z 명시 detect 의무

v0.1.473 — v0.1.473 — F8 키 Tab 전수 시퀀스 (자동화 PostMessage 한계 우회)

v0.1.473 v0.1.473 — F8 키 Tab 전수 시퀀스 (자동화 PostMessage 한계 우회) zip release notes GitHub
핵심 변경
• Bootstrap.Update 안 F8 키 detect → 100회 자동 Tab + capture sequence
• 매 0.6s 마다 1 Tab → seq-{NNN}-{name}.png 캡처
• 100회 전수 = 60s 소요
• F8 PostMessage 1회 = 모든 capture 자동 (PostMessage 다중 한계 우회)
사용자 명시 정합
"못한다 하지말고 하는방법을 찾도록" — PostMessage 한계 우회 path 발견.
영향 파일
• Bootstrap.cs ~60줄 추가 (F8 sequence)
다음 stable seal 시 제거 의무 (binary-search-code-tracking 룰 정합)

v0.1.472 — v0.1.472 — focus-tab-navigation cap cleanup (진단 로그 제거 + 룰 다이어트)

v0.1.472 v0.1.472 — focus-tab-navigation cap cleanup (진단 로그 제거 + 룰 다이어트) zip release notes GitHub
핵심 변경
• Bootstrap.Update [focus-diag] allFocusable 진단 로그 제거 (10줄)
• 룰 다이어트:
◦ focus-key-isolation.md 204→100 (-51%)
◦ focus-tab-navigation.md 239→122 (-49%)
◦ spec-completion-reminder.md 100 (신설, 적정)
본 cap 종합 (v0.1.446~472, 27 빌드, ~6h)
사용자 명시 SSOT r001+r002+r003 모든 영역 코드 적용:
• §A 메뉴바 + Enter + 방향키 + 좌측 패널 + Inspector AxisField + motor-section + viewport-focus-anchor
• §B Tab 순회 (count=93 정합)
• §C Alt 단독 메뉴바 활성화 (Windows 표준)
• 자동화 검증 11+/14 시나리오 PASS
영향 파일
• Bootstrap.cs 진단 로그 ~10줄 제거
• 룰 3건 다이어트

v0.1.471 — v0.1.471 — motor-section focusable=true (r001 §B-3 정합)

v0.1.471 v0.1.471 — motor-section focusable=true (r001 §B-3 정합) zip release notes GitHub
핵심 변경
• motor-section VisualElement focusable=true 명시 (BindUI 안 ~3줄)
• 사용자 명시 r001 §B-3 "하단항목 (모터리스트) 전체" 정합
영향 파일
• Bootstrap.cs L1163~ (~5줄)

v0.1.470 — v0.1.470 — 좌표계 Button name 부여 (coord-world-btn / coord-local-btn)

v0.1.470 v0.1.470 — 좌표계 Button name 부여 (coord-world-btn / coord-local-btn) zip release notes GitHub
핵심 변경
• Inspector "월드"/"로컬" Button name 부여 — coord-world-btn/coord-local-btn
• 진단 로그 추적성 향상 + 향후 다른 영역 식별 가능
영향 파일
• Bootstrap.cs L5934/5940 (~2줄)
잔존 audit (다음 cycle)
• 모터리스트 motor-row VisualElement (Button 아님) — focus 단위 검토 의무 (사용자 명시 "각 하단항목 버튼들이나 목록전체")

v0.1.469 — v0.1.469 — filter 회귀 fix (text-element 제거)

v0.1.469 v0.1.469 — filter 회귀 fix (text-element 제거) zip release notes GitHub
v0.1.468 회귀
filter "text-element" 추가가 모든 Button (unity-button + unity-text-element class 보유) 제외. count 108→9. 메뉴바 사라짐.
fix
text-element filter 제거. __selectable 만 유지 (TextField 안 text element).
영향 파일
• Bootstrap.cs filter 1줄 제거

v0.1.468 — v0.1.468 — TextElement __selectable filter (TextField 안 text 제외)

v0.1.468 v0.1.468 — TextElement __selectable filter (TextField 안 text 제외) zip release notes GitHub
v0.1.467 진단 결과
count 146→108. AxisFieldScrubElement (Inspector X/Y/Z) 도달 PASS. 그러나 TextElement (__selectable) 사이에 끼움.
fix
class __selectable / text-element filter 추가.
영향 파일
• Bootstrap.cs ~2줄 추가

v0.1.467 — v0.1.467 — class filter 보강 (ListView 안 ScrollerSlider 제외)

v0.1.467 v0.1.467 — class filter 보강 (ListView 안 ScrollerSlider 제외) zip release notes GitHub
v0.1.466 진단 결과
allFocusable 14번째 = ?(VisualElement)[unity-base-field__input.unity-base-slider__input] — ListView 안 scroll slider input.
fix
class StartsWith("unity-") + 키워드 (slider/scroller/scroll-view/base-field/__input) filter 추가.
영향 파일
• Bootstrap.cs ~6줄 추가 filter

v0.1.466 — v0.1.466 — allFocusable 진단 보강 (className + top20)

v0.1.466 v0.1.466 — allFocusable 진단 보강 (className + top20) zip release notes GitHub
진단 목적
v0.1.465 결과 — count 146, top15에 익명 (VisualElement) 14/15번째 등장. className 추가 진단으로 구분 식별.
영향 파일
• Bootstrap.cs L4206~ 진단 로그 보강 (~5줄)

v0.1.465 — v0.1.465 — ListView 내부 unity-* element Tab 순회 제외 (r001 정합)

v0.1.465 v0.1.465 — ListView 내부 unity-* element Tab 순회 제외 (r001 정합) zip release notes GitHub
v0.1.464 진단 결과
allFocusable count=171 / top15 = tab-file ~ tab-help (7) + sidebar-collapse + parts-toolbar 4 + part-list (ListView) + unity-content-container (ListView 내부) + unity-slider (스크롤바) + ...
사용자 명시 r001 "각 목록은 포커스 X / 목록 전체만 포커스 O" 위반.
fix
Tab navigation 동적 query에 unity-* prefix filter 추가:
`csharp
&& !(ve.name != null && ve.name.StartsWith("unity-"))
`
영향 파일
• Bootstrap.cs L4214~ (1줄 추가)
검증
• allFocusable count 줄어들 것 (171 → ~150 추정)
• Tab N회 후 Inspector "월드" → X/Y/Z → 다른 element 정확히 도달 확인

v0.1.464 — v0.1.464 — Tab navigation 진단 (allFocusable name 출력)

v0.1.464 v0.1.464 — Tab navigation 진단 (allFocusable name 출력) zip release notes GitHub
진단 목적
v0.1.463 AxisField focusable=true 추가 후 Tab 9회 결과 = Inspector "월드" 좌표계 button outline 만 visible. Inspector X/Y/Z 도달 안 함. allFocusable 순서 + Inspector 영역 도달 여부 확인 필요.
핵심 변경
• Bootstrap.Update Tab key detect 시 allFocusable.Take(15) name 출력
• 다음 stable seal 시점 제거 의무
영향 파일
• Bootstrap.cs L4205~ 진단 로그 1줄 추가

v0.1.463 — v0.1.463 — Inspector AxisField focusable=true (사용자 명시 r001 §B-2 누락 보강)

v0.1.463 v0.1.463 — Inspector AxisField focusable=true (사용자 명시 r001 §B-2 누락 보강) zip release notes GitHub
사용자 메타 피드백 (~13:40 KST)
"메뉴바쪽만 지시한게 아닐텐데" — 본 cap 사용자 명시 r001 §B (좌측 패널 Tab 순회) 영역 audit 누락 발견. AxisFieldElement/Vector3FieldElement/AxisFieldScrubElement = VisualElement default focusable=false → Inspector X/Y/Z 버튼 Tab 순회 누락.
핵심 변경
• AxisFieldElement constructor → focusable = true (1줄)
• Vector3FieldElement constructor → focusable = true (1줄)
• AxisFieldScrubElement constructor → focusable = true (1줄)
룰 영구화
.claude/rules/spec-completion-reminder.md 신규 — 사용자 명시 spec 사이클 종료 시 매핑 검증 의무 영구화. 국부 영역 매몰 재발방지.
잔존 audit 영역 (다음 cycle)
• 모터리스트 구조 검토 (표 row vs 별도 element + focusable 명시)
• 검색창 (search-host) — 사용자 명시 "각 버튼들과 검색창" → 명시 포함 여부 재확인
• 컴포넌트 각 항목 (Inspector TextField/DropdownField)
영향 파일
• Assets/Scripts/UI/AxisFieldElement.cs L62 + L162 (focusable=true 추가 2건)
• Assets/Scripts/UI/AxisFieldScrubElement.cs L76 (focusable=true 추가)
• .claude/rules/spec-completion-reminder.md 신규

v0.1.462 — v0.1.462 — Tab 시 메뉴바 전수 outline reset (edge case fix)

v0.1.462 v0.1.462 — Tab 시 메뉴바 전수 outline reset (edge case fix) zip release notes GitHub
v0.1.461 audit 결과
Tab 8회 후 cursor reset 했음에도 "파일(F)" outline 잔존 (Inspector "월드" outline과 동시 visible). FocusOutEvent 미발화 edge case 확정.
fix
Tab 키 detect 시 _lnbTabs[i] 8개 전수 inline outline 0 reset → FocusInEvent 가 nextIdx 만 적용. 안전망 강화.
영향 파일
• Bootstrap.cs Tab navigation 안 _lnbTabs 전수 reset (~12줄)

v0.1.461 — v0.1.461 — BetweenMs 700 + Tab 시 옛 outline 명시 clear (FocusOut 이중 안전망)

v0.1.461 v0.1.461 — BetweenMs 700 + Tab 시 옛 outline 명시 clear (FocusOut 이중 안전망) zip release notes GitHub
핵심 변경 (자동화 도구 + 코드 동시 보강)
• send-keys-to-factory00.ps1 BetweenMs default 350 → 700 (Tab 다중 timing 정합)
• capture-with-keys-1920.sh sleep + CAP_DELAY 동적 (key 수 기반)
• Bootstrap.Update Tab navigation 안 옛 focused element outline 명시 clear (~8줄)
v0.1.461 자동화 검증 (FT-2 PASS 확정)
v0.1.460 FT-2 시도 — Tab 8회 → "월드" Inspector button outline visible. 옛 "파일(F)" outline 잔존 발견 → FocusOutEvent 미발화 가능성.
fix path
• Tab navigation 안 옛 focused element borderWidth=0 + backgroundColor=Null 명시 clear
• FocusOutEvent root.RegisterCallback 안전망 보존 (기존)
• 이중 안전망 — UI Toolkit FocusOut 발화 안 됨 케이스 대비
영향 파일
• Tools/qa/send-keys-to-factory00.ps1 L8 BetweenMs default 700
• Tools/qa/capture-with-keys-1920.sh L33~ 동적 CAP_DELAY + L56 동적 sleep
• Bootstrap.cs Tab navigation 안 outline clear (~8줄)
검증
• FT-2 Tab 8회 후 "월드" Inspector outline visible + "파일(F)" outline 사라짐 (이중 안전망 PASS)

v0.1.460 — v0.1.460 — Alt 단독 메뉴바 활성화 (Q3 윈도우 표준)

v0.1.460 v0.1.460 — Alt 단독 메뉴바 활성화 (Q3 윈도우 표준) zip release notes GitHub
핵심 변경
• Bootstrap.Update 안 Alt down + up detect path
• Alt down 시점 기록 (_altDownTime) + Alt down 중 다른 키 detect (_altOtherKey)
• Alt up 시점 — 다른 키 없음 + 1.0s 이내 → _lnbTabs[0]?.Focus()
• Alt+글자 mnemonic 보존 (다른 키 발화 시 _altOtherKey=true → 활성화 안 함)
Windows 표준 정합
• Alt 단독 (down + up 사이 다른 키 X) = 메뉴바 활성화
• Alt+글자 = mnemonic (옛 영역 보존)
• F10 = 자체 측 설정 토글 (옛 영역 보존, 충돌 회피)
영향 파일
• Bootstrap.cs L4194~ Alt 단독 detect (~20줄 추가)
• _altDownTime / _altOtherKey field 추가
검증 시나리오 (자동화 시도)
• Alt down + up → 메뉴바 첫 헤더 outline visible
• Alt + F → mnemonic 옛 동작 보존 (메뉴바 활성화 X)
focus-tab-navigation-spec r002 추가
사용자 명시 "Q3 윈도우 표준 적용" — Alt 단독 (Windows 표준) 추가.

v0.1.459 — v0.1.459 — ESC dropdown 닫기 cascade 보강 (FT-12 fix)

v0.1.459 v0.1.459 — ESC dropdown 닫기 cascade 보강 (FT-12 fix) zip release notes GitHub
v0.1.458 진단 결과
FT-12 시나리오 (Tab + ↓ + ESC) 결과 dropdown 여전 열림. Bootstrap.Update L4440 ESC cascade 안 dropdown 닫기 분기 부재 — focusedEl.Blur() 만 처리.
fix
L4440 ESC cascade 안 focusedEl.Blur() 이전 우선순위로 dropdown 닫기 분기 추가:
_lnbActiveIdx >= 0 → HideLnbDropdown() + _lnbTabs[restoreIdx]?.Focus() 메뉴바 헤더 복귀
영향 파일
• Bootstrap.cs L4445~ ESC cascade dropdown 분기 추가 (~10줄)
검증
• FT-12: Tab + ↓ + ESC → dropdown 닫힘 + 메뉴바 헤더 outline 복귀 PASS
• 옛 ESC cascade (ContextMenu / drag / SubWindow / focus blur / 선택 해제) 보존
focus-tab-navigation-spec r002 정합
"dropdown 안 명령 focus + ESC → dropdown 닫기 + 메뉴바 헤더 focus 복귀" 정합.

v0.1.458 — v0.1.458 — P5 3D viewport dummy focusable + outline 예외 (focus-tab-navigation-spec 완성)

v0.1.458 v0.1.458 — P5 3D viewport dummy focusable + outline 예외 (focus-tab-navigation-spec 완성) zip release notes GitHub
핵심 변경
• VisualElement _viewportFocusAnchor 추가 (root 마지막 자식, focusable=true, pickingMode=Ignore, -1000px 화면 밖)
• FocusInEvent / FocusOutEvent 안 viewport-focus-anchor 예외 (outline 안 적용)
• Tab 동적 query 자동 포함 — root 마지막 자식이므로 순회 마지막 step
사용자 명시 SSOT 정합
사용자 r001: "좌측 레이아웃 이후에는 3d영역이 포커스된다. 3d영역은 포커스 시 아웃라인을 그리지 않는다. 이 상태에서 tab을 누르면 다시 file로 포커스가 된다."
v0.1.458 = viewport-focus-anchor + Tab 순회 마지막 + outline 예외. 다음 Tab → tab-file 복귀 (allFocusable[0]).
영향 파일
• Bootstrap.cs L969 _viewportFocusAnchor field 추가
• Bootstrap.cs L4013~ viewport-focus-anchor 생성 (~12줄)
• Bootstrap.cs L4030~ FocusIn 예외 (~2줄)
• Bootstrap.cs L4045~ FocusOut 예외 (~2줄)
검증 시나리오
• Tab N회 (메뉴바 + 좌측 패널 다 통과) → viewport-focus-anchor focus → outline 안 보임
• 다음 Tab → tab-file outline visible (순환 cycle)

v0.1.457 — v0.1.457 — focus cleanup (진단 로그 제거 + 무효 USS rule 정리 + 룰 영구화)

v0.1.457 v0.1.457 — focus cleanup (진단 로그 제거 + 무효 USS rule 정리 + 룰 영구화) zip release notes GitHub
핵심 변경
• Bootstrap.Update 안 [focus-diag] 진단 로그 제거 (~10줄)
• Tab navigation 안 Debug.Log 제거
• components.uss :focus rule 영구 제거 (~28줄 → 코멘트 6줄)
• ribbon.uss .is-focused rule 영구 제거
• .claude/rules/focus-tab-navigation.md 영구화 — UI Toolkit :focus 동작 X 학습 + 권장/금지 패턴
영구 fix path (룰 영구화)
• 동적 query Tab navigation (Bootstrap.Update Input.GetKeyDown(Tab))
• FocusInEvent/FocusOutEvent root.RegisterCallback (BindUI 안)
• inline .style set (border 3px gold + background gold-soft)
영향 파일
• Bootstrap.cs L4150~ 진단 로그 제거 + Debug.Log 제거 (~13줄 제거)
• Theme/components.uss L427~452 :focus rule 영구 제거 (코멘트 6줄로)
• Components/ribbon.uss .is-focused 영구 제거 (코멘트 6줄로)
• .claude/rules/focus-tab-navigation.md UI Toolkit :focus 학습 절 영구화 (~70줄 추가)
검증
• Tab → 메뉴바 outline visible 유지 (v0.1.456 동작 보존)
• Player.log [focus-diag] 출력 0건 (cleanup 확정)
• USS rule 정리 후 visible outline 동작 (FocusInEvent path만)

v0.1.456 — v0.1.456 — P4 동적 query 기반 Tab navigation (좌측 패널 자동 확장)

v0.1.456 v0.1.456 — P4 동적 query 기반 Tab navigation (좌측 패널 자동 확장) zip release notes GitHub
핵심 변경
• Bootstrap.Update Tab navigation = 동적 query (rootEl.Query().Where(focusable))
• UXML 자식 순서 자동 보존 (사용자 명시 모듈화 원칙 — 상위→하위 / 위→아래 / 왼쪽→오른쪽)
• focus-dummy / search-host 제외 (default focus 영역)
• visible=True (display != None) 필터 — dropdown 닫힘 시 안 명령 자동 skip
적용 영역 확장
• 메뉴바 헤더 (8) — _lnbTabs[0~6]
• LNB dropdown 안 명령 button (열린 dropdown만) — focusable=true + display=Flex 시
• 좌측 패널 button (parts-toolbar 4 + sidebar-collapse + sidebar-mini-rail 등 자동 포함)
• Inspector 안 button / Vector3FieldElement (focusable=true 자동)
• 모터리스트 button
영향 파일
• Bootstrap.cs L4150~ Tab navigation 동적 query로 교체 (~30줄 변경)
검증 시나리오
• Tab 1회 → allFocusable[0] = tab-file (메뉴바 첫번째)
• Tab 2회 → tab-edit
• Tab N회 → 좌측 패널 button 도달
• Shift+Tab → 역순
• Player.log [focus-diag] allFocusable name 변화 추적
P5 예약
3D viewport dummy focusable + outline 예외 (별도 cycle)

v0.1.455 — v0.1.455 — FocusInEvent / FocusOutEvent 일원화 (모든 focusable element 자동 outline)

v0.1.455 v0.1.455 — FocusInEvent / FocusOutEvent 일원화 (모든 focusable element 자동 outline) zip release notes GitHub
핵심 변경
• root.RegisterCallback FocusInEvent/FocusOutEvent (TrickleDown capture phase) — 모든 focusable element 자동 outline
• focus 받을 때: border 3px gold + background gold-soft
• focus 잃을 때: border 0 + background null clear
• focus-dummy / focus-dummy name 제외 (default focus 영역)
• Tab navigation 안 inline style set 코드 제거 (중복)
적용 영역
• 메뉴바 헤더 (_lnbTabs[i]) — Tab + Focus() 호출 시
• dropdown 안 명령 button — ↓ + 첫 cmd Focus 시 + ↑↓ 순환 시
• ←/→ cascade 다음 메뉴 Focus 시
• 향후 모든 focusable element (좌측 패널 button / Inspector field 등)
v0.1.454 진척
visible outline 메뉴바 헤더 PASS 확정. dropdown 열림 ↓ 시각 PASS.
본 v0.1.455 = 일원화 + dropdown 안 명령 button outline 자동 적용 보장.
영향 파일
• Bootstrap.cs L4011~ FocusInEvent/FocusOutEvent root.RegisterCallback (~35줄 추가)
• Bootstrap.cs L4150~ Tab navigation 안 inline style set 제거 (~25줄 → 3줄)
검증 시나리오
• Tab → 메뉴바 outline 자동
• ↓ → dropdown 열림 + 첫 cmd outline 자동
• ↑/↓ → cmd 순환 + outline 이동 자동
• ←/→ → 다른 메뉴 cascade + outline 이동
• Esc → dropdown 닫기 + 메뉴바 헤더 outline 자동

v0.1.454 — v0.1.454 — focus outline .style 직접 set (USS 우회)

v0.1.454 v0.1.454 — focus outline .style 직접 set (USS 우회) zip release notes GitHub
핵심 변경
• _lnbTabs[i].Focus() 시 inline .style 직접 set (USS rule 우회)
• border 4 방향 3px width + gold-primary 색상 + gold-soft background
• 다른 메뉴 → 0px clear + background null
v0.1.453 진단 결과
class 명시 (AddToClassList "is-focused") 적용했지만 [focus-diag] border=0px 여전.
root cause: ribbon.uss .is-focused USS rule 적용 안 됨 (가능성: USS load 순서 / class 적용 timing / UI Toolkit USS spec 차이).
fix path
• inline .style 직접 set — USS rule 우선순위 무관
• 즉시 적용 보장 (UI Toolkit 표준)
• 다른 메뉴 inline style clear (Toggle 시 자동 해제)
영향 파일
• Bootstrap.cs L4150~ inline style set (~25줄)
검증
• Tab → tab-file [focus-diag] border=3px / background gold visible
• crop capture 안 visible outline 가시 PASS 기대

v0.1.453 — v0.1.453 — focus outline class 명시 path (UI Toolkit :focus pseudo-class 동작 안 됨 우회)

v0.1.453 v0.1.453 — focus outline class 명시 path (UI Toolkit :focus pseudo-class 동작 안 됨 우회) zip release notes GitHub
v0.1.452 진단 결과 (root cause 확정)
Player.log [focus-diag] = focused=tab-file Button + border=0px color=RGBA(0, 0.416, 0.651, 1).
root cause = UI Toolkit :focus pseudo-class 동작 보장 안 됨. USS :focus rule 적용 안 됨.
fix path
• Bootstrap _lnbTabs[i].Focus() 호출 시 AddToClassList("is-focused") 동시 호출
• 다른 _lnbTabs RemoveFromClassList("is-focused")
• ribbon.uss .c-lnb__menu.is-focused { border 3px gold + background gold-soft } 명시
• :focus selector 폐기 (자체 측 v0.1.420+ 적용 :focus 모두 동작 안 했음 — 옛 룰 정합 fix 필요)
영향 파일
• Bootstrap.cs L4150~ Tab navigation class 명시 (~12줄 변경)
• ribbon.uss L54~ .is-focused class 추가 (~12줄)
검증 path
• Tab → tab-file Focus + is-focused class
• Player.log [focus-diag] border=3px / background gold-soft 확인
• crop capture 안 가시 outline 가시 확인 (메뉴바 영역 확대)

v0.1.452 — v0.1.452 — focus resolvedStyle 진단 (border-width 실제 값)

v0.1.452 v0.1.452 — focus resolvedStyle 진단 (border-width 실제 값) zip release notes GitHub
핵심 변경
• Bootstrap.Update() [focus-diag] 진단 보강 — focused element의 resolvedStyle.borderLeftWidth + borderLeftColor 출력
• USS :focus 적용 여부 직접 확인 path
진단 목적
v0.1.451 빌드 + ribbon.uss :focus 강화 후에도 crop 시각 outline 안 보임.
focused=tab-file 확정 (Player.log) 그러나 visible 0 → USS :focus 적용 여부 직접 확인 의무.
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L4145~ 진단 로그 보강 (~3줄)
검증
• Tab 후 [focus-diag] 안 "border=2px color=rgb(255,217,115)" 출력 시 USS 적용 PASS — 시각 한계 가능성
• "border=0px color=rgb(0,0,0,0)" 출력 시 USS 미적용 — 추가 fix path (class 명시 등)

v0.1.451 — v0.1.451 — focus outline ribbon.uss 안 :focus 직접 (USS specificity 강화)

v0.1.451 v0.1.451 — focus outline ribbon.uss 안 :focus 직접 (USS specificity 강화) zip release notes GitHub
핵심 변경
• ribbon.uss 안 .c-lnb__menu:focus 직접 추가 (~11줄)
• border-width 2px + gold-primary 색상 (visible 가시성 강화)
• components.uss 의 :focus (1px accent-primary)가 ribbon.uss base border-width:0 override 안 되는 USS load 순서 회피
v0.1.450 진단 결과
Tab navigation fix PASS — focused element = focus-dummy → tab-file (Button) 변화 확정 (Player.log 검증).
그러나 visible outline 안 보임 — root cause = ribbon.uss:34 .c-lnb__menu { border-width: 0 } base rule이 :focus 보다 우선 (USS load 순서).
fix path
• ribbon.uss 동일 파일 안 :focus → specificity 동일 + last wins
• 2px border + gold-primary 색상 (시각 더 강력)
영향 파일
• Assets/UI/Components/ribbon.uss L54~ :focus 추가 (~11줄)
검증 시나리오
• Tab → tab-file focus → border 2px gold visible
• ←/→ 다른 메뉴바 → cascade focus + outline visible

v0.1.450 — v0.1.450 — Tab 명시 Focus() 호출 + 진단 로그 (v0.1.449 fix 실효 0 회귀)

v0.1.450 v0.1.450 — Tab 명시 Focus() 호출 + 진단 로그 (v0.1.449 fix 실효 0 회귀) zip release notes GitHub
핵심 변경
• Input.GetKeyDown(Tab) detect 시 [focus-diag] TAB KEY DETECTED 진단 로그
• NavigationMoveEvent 우회 → _lnbTabs[i].Focus() 직접 호출 path
• focus-dummy / root → _lnbTabs[0] / _lnbTabs[i] → 다음 [i+1] (Shift = [i-1]) 명시
v0.1.449 진단 결과
[focus-diag] focused=focus-dummy 영구. NavigationMoveEvent 발화는 SendEvent 했지만 focus 이동 0.
가설: focusController 자동 navigation은 NavigationMoveEvent 처리에 추가 조건 (focusable=true + visible + pickable). 명시 Focus() 호출이 더 직접적.
fix path 우회
• NavigationMoveEvent 우회 — _lnbTabs[i].Focus() 직접 호출 (UI Toolkit Focusable.Focus() API)
• Shift+Tab = 반대 방향
• 진단 로그 추가 — TAB KEY DETECTED 발화 여부 + Focus 호출 path 확인
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L4150~ Tab navigation 명시 영역 변경 (~40줄)
자동화 검증 시나리오
• 빌드 직후 PostMessage Tab → Player.log "[focus-diag] TAB KEY DETECTED" 발화 확인
• Focus() 호출 후 다음 frame [focus-diag] focused=tab-file 등 변화 확인

v0.1.449 — v0.1.449 — Tab/Shift+Tab 명시 navigation 발화 (v0.1.448 진단 fix)

v0.1.449 v0.1.449 — Tab/Shift+Tab 명시 navigation 발화 (v0.1.448 진단 fix) zip release notes GitHub
핵심 변경
• Bootstrap.Update() 안 Input.GetKeyDown(Tab) detect + focusController.SwitchFocusOnEvent 명시 호출
• IsAnyTextFieldFocused 가드 — TextField 안 Tab은 정상 입력 동작 유지
v0.1.448 진단 결과 (root cause 확정)
Player.log [focus-diag] 출력 = focused=focus-dummy 영구 고정. PostMessage Tab 키가 UI Toolkit Panel KeyDownEvent 도달 안 함. Unity Input.GetKey 영역과 UI Toolkit Panel input system 분리.
fix path
• Bootstrap.Update() 안 Input.GetKeyDown(Tab) 매 frame polling
• focusController 명시 NavigationMoveEvent (Next / Previous direction Shift+Tab)
• IsAnyTextFieldFocused 가드 — Inspector TextField 안 Tab 정상
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L4150~ (Tab navigation 명시 ~18줄 추가)
자동화 검증
• 빌드 직후 PostMessage Tab → Input.GetKeyDown(Tab) 발화 → NavigationMoveEvent → focus 이동
• Player.log [focus-diag] 안 focused element 변화 확인 가능 (focus-dummy → _lnbTabs[0] 등)
다음 stable seal
• 진단 로그 [focus-diag] 제거 의무 (binary-search-code-tracking 룰 정합)
• Tab navigation 명시 fix는 영구 유지

v0.1.448 — v0.1.448 — focus 진단 로그 추가 (v0.1.446+447 자동화 검증)

v0.1.448 v0.1.448 — focus 진단 로그 추가 (v0.1.446+447 자동화 검증) zip release notes GitHub
핵심 변경
• Bootstrap.Update() 안 0.5s 주기 focused element name + type 출력
• 다음 stable seal 시점 제거 의무 (binary-search-code-tracking 룰)
진단 목적
v0.1.446 P1+P2+P3 + v0.1.447 focus outline USS 적용 후 capture-with-keys Tab/Enter 결과 visible outline 안 보임 / dropdown 안 열림.
PostMessage Tab/Enter 키 vs UI Toolkit NavigationTabEvent 발화 별도 영역 가능성 진단.
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L4138~4148 (Update 시작점 진단 ~7줄)
자동화 검증 path
• Tab/Enter PostMessage 시나리오 후 Player.log focused element 변화 분석
• focused 가 null 또는 _focusDummy 고정 → Tab navigation 발화 안 됨
• focused 가 _lnbTabs[0] 등으로 변경 → 정상. outline 별도 검증

v0.1.447 — v0.1.447 — focus outline USS 추가 (v0.1.446 P1~P3 + visible outline 보완)

v0.1.447 v0.1.447 — focus outline USS 추가 (v0.1.446 P1~P3 + visible outline 보완) zip release notes GitHub
핵심 변경
• components.uss 끝에 :focus 스타일 추가 (~25줄)
◦ .c-lnb__menu:focus / .c-lnb__item:focus / Button:focus / .unity-button:focus
◦ .unity-text-field:focus / .unity-base-field:focus
• border-color = var(--accent-primary) + border-width 1px
사용자 명시 SSOT 정합
사용자 r001 명시: "현재 프로퍼티 영역처럼 아웃라인으로 포커스 되었음을 알 수 있어야 한다"
v0.1.446 (P1~P3) 적용 후 visible focus outline 부재 — 본 USS 추가로 시각 검증 가능.
영향 파일
• Assets/UI/Theme/components.uss 끝 ~25줄 추가
검증 시나리오 (자체 자동화 + 사용자 PC)
• Tab → 메뉴바 헤더 focus → 골드 border 1px visible
• Tab → 좌측 패널 button focus → 동일
• Inspector TextField focus → 동일
• 메뉴바 헤더 focus + ↓ → dropdown 열기 + 첫 명령 focus + outline
• ←/→ 다른 헤더 cascade + outline
• ↑/↓ dropdown 안 명령 순환 + outline

v0.1.446 — v0.1.446 — focus-tab-navigation P1+P2+P3 통합 (메뉴바 Tab 순회 + Enter + 방향키)

v0.1.446 v0.1.446 — focus-tab-navigation P1+P2+P3 통합 (메뉴바 Tab 순회 + Enter + 방향키) zip release notes GitHub
핵심 변경 (사용자 명시 SSOT focus-tab-navigation-spec r001+r002)
• P1: _lnbTabs[i].focusable = true (L1678) — Tab 순회 + Enter 자동 활성화
• P2: dropdown 안 cmdBtn.focusable = true (L1700) — Tab 순회 + Enter 자동
• P3: 방향키 KeyDownEvent 핸들러 (~80줄 신규)
◦ 메뉴바 헤더: ←/→ 다른 헤더 (순환, cascade) + ↓ dropdown 열기 + 첫 명령 focus
◦ dropdown 안 button: ↑/↓ 명령 순환 + ←/→ 다른 메뉴 cascade + ESC dropdown 닫기 + 헤더 focus 복귀
• QA-085 보호: Space KeyDownEvent에서 StopPropagation (카메라 상승 키 보존)
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L1670~1770 (~100라인 추가, 옛 ~35라인 변경/확장)
사용자 명시 SSOT
• wiki/topics/focus-tab-navigation-spec.md (r002)
• .claude/rules/focus-tab-navigation.md
사용자 검증 시나리오 (Stage 2 — 사용자 로컬 QA 명시)
• Tab → 메뉴바 헤더 순회 (focus outline)
• 메뉴바 헤더 focus + Enter → dropdown 열기
• 메뉴바 헤더 focus + ↓ → dropdown 열기 + 첫 명령 focus
• 메뉴바 헤더 focus + ←/→ → 다른 헤더 (dropdown 열려있으면 cascade)
• dropdown 안 명령 focus + Enter → 명령 실행
• dropdown 안 명령 focus + ↑/↓ → 순환 이동
• dropdown 안 명령 focus + ←/→ → 다른 메뉴 cascade
• dropdown 안 명령 focus + ESC → dropdown 닫기 + 헤더 focus 복귀
• 메뉴바 헤더 focus + Space → 카메라 상승 (QA-085 보호 — focus 차단 안 됨)
P4/P5 다음 사이클
• P4: Tab 순회 순서 audit (좌측 레이아웃 상단/중단/하단 → 3D viewport 복귀)
• P5: 3D viewport dummy focusable + USS outline 예외
• Q3 윈도우 표준 추가: Alt 단독 메뉴바 활성화 / Ctrl+Tab 등 (별도 cycle)

v0.1.445 — v0.1.445 — QA-128 R-1+R-2 small fix (S0050 r002 사양 정합)

v0.1.445 v0.1.445 — QA-128 R-1+R-2 small fix (S0050 r002 사양 정합) zip release notes GitHub
핵심 변경
• MaxAngleDeg 필드 + 호출처 영구 제거 (R-1, spec L33 명시 폐기)
• _actualRotateAngle 계산 단순화 (Mathf.Min 제거 → RotateAngle - Stopper)
• Inspector "최대각도(°)" 행 제거
• RotationRadiusMm 코멘트 명확화 (R-2): "부품 origin → 회전 중심축 거리"
영향 파일
• Assets/Scripts/Actuators/PneumaticRotaryCylinderActuator.cs L30~33 + L42~44 + L122~124 (필드 + 코멘트 + 계산)
• Assets/Scripts/Game/Factory00Bootstrap.cs L7584~7587 (Inspector 행)
• Assets/Scripts/Actuators/PneumaticCylinderActuator.cs L68~71 (옛 코멘트 동기)
위험 평가
• 변경 ~10 라인 — critic 의무 미달
• .twn 직렬화에 MaxAngleDeg 가 잔존하더라도 JsonUtility deserialize 시 무시 (안전)
• 회귀 위험: 옛 .twn 안 MaxAngleDeg < RotateAngle 인 케이스 — 본 fix 전후 동일 (MaxAngleDeg 적용 안 됨이라 동일)
R-3 + R-4 (다음 cap, 사용자 명시 의무)
• R-3: 구동 범위 씬 표시 (원호 Visualizer 신규)
• R-4: PortArrivalSensor 회전 패턴 (S0002 r004 §5-4 미러) — 이미 v0.1.335 P1.4 구현, DetectionRangeDeg 1.0 정합 확인
사용자 검증 시나리오 (Stage 2)
• Inspector 회전 실린더 카드에 "최대각도(°)" 행 부재 PASS
• 회전 동작 시 실 구동 범위 = RetractAngle + Stopper ~ RotateAngle - Stopper PASS
• RotationRadiusMm 의미 명확화 코멘트 (코드 검토 시점)

v0.1.444 — v0.1.444 — QA-104 모델링 임포트 7차 fix (LNB dropdown worldBound 영역 통과)

v0.1.444 v0.1.444 — QA-104 모델링 임포트 7차 fix (LNB dropdown worldBound 영역 통과) zip release notes GitHub
핵심 변경
• L4115 inViewport && _lnbActiveIdx 가드에 overActiveDropdown 검증 추가 (8줄)
• 사용자 click 이 active dropdown 의 worldBound 안 → HideLnbDropdown 호출 skip
• v0.1.414 fix 가정 "LNB dropdown은 좌측 패널 좌표 영역" 오류 — 도구/도움말 등 우측 tab dropdown은 x > LEFT_W 영역
• cmd-import-step 은 "도구" tab (idx 5) dropdown 안 → mousePosition.x > 320 → inViewport=true → HideLnbDropdown 호출 → button click 차단 회귀
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L4115~4129 — overActiveDropdown worldBound 검증 추가 (8줄)
위험 평가
• 변경 8 라인 — critic 의무 미달
• 모든 LNB dropdown (파일/편집/뷰/부품/실행/도구/도움말) 안 click 통과
• dropdown 외 viewport click 은 HideLnbDropdown 호출 유지 (QA-097 fix 보존)
사용자 검증 시나리오 (Stage 2)
• 도구 메뉴 → 모델링 IMPORT click → 파일 선택 dialog 출현 PASS 의무
• 파일/편집/뷰/부품/실행/도움말 메뉴도 동일하게 click 정상 PASS
• 3D viewport click 시 dropdown 정상 닫힘 (QA-097 fix 보존)
v0.1.443 동봉 (WASD focus-dummy REAL FIX)
v0.1.443 빌드에 이미 포함된 WASD fix 도 함께 게시. 두 fix 모두 v0.1.444 dll 안.

v0.1.443 — v0.1.443 — WASD 무동작 REAL FIX (focus-dummy IsAnyUIFocused 통과)

v0.1.443 v0.1.443 — WASD 무동작 REAL FIX (focus-dummy IsAnyUIFocused 통과) zip release notes GitHub
핵심 변경
• IsAnyUIFocused() — focused == _focusDummy + name=="focus-dummy" 통과 추가
• v0.1.442 QA-123 polling 가드 실효 0 회귀 — startup L3921 _focusDummy.Focus() 자체가 root cause
• "잠깐씩 움직이기도 한다" 정합 — click 시 focus 잠깐 옮겨감 → polling 재 focus → 차단
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L478~485 — IsAnyUIFocused 가드 보강 (3줄 추가)
위험 평가
• 변경 3 라인 — critic 의무 미달
• _focusDummy 의도된 default focus (검색 입력 막기 위한 dummy) 영향 X
• 다른 UI element focus 시 정상 차단 유지 (사용자 click 한 메뉴 button / TextField / Dropdown)
자율 검증 시나리오 (어시스턴트 측 PostMessage 자동화)
• 빌드 직후 W/A/S/D PostMessage WM_KEYDOWN → 카메라 이동 검증 (PrintWindow 캡처)
• ESC 키 → focus 해제 → W/A/S/D 즉시 동작 PASS
사용자 검증 시나리오 (Stage 2)
• 14 시나리오 #2: TextField focus → 3D click → wasd 카메라 이동 PASS
• 14 시나리오 ALL: focus 기조 + Inspector Scrubber 재검증 가능

v0.1.442 — v0.1.442 — QA-123 + QA-124 자율 fix (focus polling 가드 + root child name)

v0.1.442 v0.1.442 — QA-123 + QA-124 자율 fix (focus polling 가드 + root child name) zip release notes GitHub
핵심 변경
• QA-124 (UI root NaN) — axisIndicator.name = "axis-indicator" + _helpOverlay.name = "help-overlay" 부여
• QA-123 (WASD 키 입력 무효) — focus-dummy polling 코드에 IsAnyUIFocused() 가드 추가 (옵션 B)
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L1167+1180 — root child name 부여
• Assets/Scripts/Game/Factory00Bootstrap.cs L4552 — IsAnyUIFocused 가드 1줄
위험 평가
• 변경 ~3 라인 — critic 의무 미달
• QA-124 = 명시적 name 부여, 회귀 영역 0
• QA-123 = 가드 추가 (polling skip 영역 확대), 옛 stepping 회귀 위험 매우 낮음
사용자 검증 시나리오 (PhotoSensor 외 추가)
• WASD 이동 중 ESC 키 입력 후 W/A/S/D 즉시 동작 PASS 의무
• Player.log 안 child[1] / child[2] / child[3] name = "axis-indicator" / "help-overlay" / "focus-dummy" 확인

v0.1.441 — v0.1.441 — Task #161 P2 SensorVec3Field → Vector3FieldElement 통합 (PhotoSensor 카드)

v0.1.441 v0.1.441 — Task #161 P2 SensorVec3Field → Vector3FieldElement 통합 (PhotoSensor 카드) zip release notes GitHub
핵심 변경
• SensorVec3Field 본문 46 → 23 라인 (-23)
Factory00.UI.Vector3FieldElement (Task #159 P1 v0.1.426 SSOT) 직접 사용
• X/Y/Z 컬러 라벨 = tokens.uss --axis-{x,y,z}-color SSOT 통합
• GetVec / SetVec 헬퍼 제거 (-2 라인)
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs L6335~6360 — SensorVec3Field 단순화
사용자 검증 시나리오 (Task #161 후속)
• PhotoSensor 카드 위치(mm) / 회전(°) 입력 PASS 의무
• X/Y/Z 컬러 라벨 표시 PASS 의무
• 입력 commit (BlurEvent + Enter) PASS 의무
회귀 영역 격리
• Inspector EditableVec3Row P3 영역 무관 (별개 카드 영역)
• 사용자 14 시나리오 (포커스 6 + Scrubber 8) 무관

v0.1.440 — QA-122 root cause 확정 + sharedassets swap fix (UI 회복)

v0.1.440 QA-122 root cause = sharedassets0.assets +112 byte. v0.1.431 archive 사본으로 swap → UI 전체 정상 렌더 회복. zip latest.zip
자율 binary search 9 빌드 (v0.1.431~v0.1.439) 결과: USS 영역 / Library cache 모두 root cause 아님 확정. archive v0.1.431.zip 직접 실행 PASS + binary diff sharedassets0.assets 단독 +112 byte 차이 식별. swap 후 Player.log ApplyGlobalKeyword 예외 0건 시각 확정.

v0.1.439 — v0.1.439 — QA-122 binary search 8차 (Library cache 백업 + fresh rebuild)

v0.1.439 v0.1.439 — QA-122 binary search 8차 (Library cache 백업 + fresh rebuild) zip release notes GitHub
v0.1.438 FAIL = USS revert만으로 회복 안 됨. Library/Bee cache hit 가설.
변경
• Library/Bee / StyleSheets / PlayerDataCache 백업 (rename to *-bak-*)
• USS 영역 = v0.1.438 동일 (본 cap 추가 모두 제거)
• 코드 영역 = v0.1.430 동일 (AxisField/Scrub/Kind 보존)
자율 검증
• PASS → Library cache root cause 확정 → publish-build-auto.sh 안 cache clear hook 검토
• FAIL → 코드 영역 root cause → 다음 cycle 코드 임시 제거

v0.1.438 — v0.1.438 — QA-122 binary search 7차 (.axis-field 3 rule 일괄 제거 = v0.1.431 회복)

v0.1.438 v0.1.438 — QA-122 binary search 7차 (.axis-field 3 rule 일괄 제거 = v0.1.431 회복) zip release notes GitHub
v0.1.437 FAIL = .axis-field / __input / .vector3-field 자체 root cause.
일괄 제거하여 v0.1.431 동일 상태로 회복.
변경
.axis-field / .axis-field__input / .vector3-field 3 rule 일괄 제거
• 본 cap USS rule 모두 제거 = v0.1.431 동일 상태
자율 검증
• PASS → .axis-field 영역 root cause 확정 → v0.1.439+ 1개씩 다시 추가
• FAIL → USS 외 영역 root cause (코드 / UXML / ProjectSettings)

v0.1.437 — v0.1.437 — QA-122 binary search 6차 (:focus rule 제거, .axis-field 단독)

v0.1.437 v0.1.437 — QA-122 binary search 6차 (:focus rule 제거, .axis-field 단독) zip release notes GitHub
v0.1.432 (:focus only) PASS / v0.1.436 (:focus + .axis-field base/input/vector3) FAIL.
가설: :focus + .axis-field 조합이 root cause.
변경
:focus rule 2 그룹 제거 (v0.1.432에서 추가했던 영역)
.axis-field / __input / .vector3-field 유지 (.axis-field__label은 v0.1.436에서 이미 제거)
자율 검증
• PASS → :focus + .axis-field 조합이 root cause → :focus rule만 단독으로 v0.1.432 시점 회복
• FAIL → .axis-field 자체 또는 __input / .vector3-field root cause

v0.1.436 — v0.1.436 — QA-122 binary search 5차 (.axis-field__label rule 제거)

v0.1.436 v0.1.436 — QA-122 binary search 5차 (.axis-field__label rule 제거) zip release notes GitHub
v0.1.435 FAIL (BEM modifier 제거해도 좌측 깨짐) → root cause = .axis-field__label / __input / .vector3-field / .axis-field base 중 1.
변경
.axis-field__label { ... } rule 단독 제거 (가장 복잡: Unity 전용 -unity-text-align / -unity-font-style / border-radius 4면 + width/height/color/margin/font-size)
.axis-field / .axis-field__input / .vector3-field 유지
자율 검증
• PASS → .axis-field__label 안 어떤 property가 root cause
• FAIL → .axis-field base / __input / .vector3-field 영역

v0.1.435 — v0.1.435 — QA-122 binary search 4차 (.axis-field BEM modifier 제거)

v0.1.435 v0.1.435 — QA-122 binary search 4차 (.axis-field BEM modifier 제거) zip release notes GitHub
v0.1.434 FAIL = .axis-field rule 또는 BEM modifier .axis-field--{x,y,z} root cause.
변경
.axis-field--x .axis-field__label { background-color: rgba(...) } 3 rule 제거
.axis-field / .axis-field__label / .axis-field__input / .vector3-field 유지
자율 검증
• PASS → BEM modifier .axis-field--x 영역 root cause → -- modifier 회피 패턴
• FAIL → .axis-field rule 또는 __label 자체 root cause → 추가 binary

v0.1.434 — v0.1.434 — QA-122 binary search 3차 (.axis-field rule 직접 rgba, var() 제거)

v0.1.434 v0.1.434 — QA-122 binary search 3차 (.axis-field rule 직접 rgba, var() 제거) zip release notes GitHub
v0.1.433 FAIL (.axis-field + var() = UI 미렌더링 회기 재현).
변경
.axis-field--{x,y,z} .axis-field__labelvar(--axis-x-color) → 직접 rgba(220, 80, 80, 0.85)
• tokens.uss --axis-{x,y,z}-color 토큰은 유지 (사용 X 상태)
자율 검증
• PASS → var() 사용이 root cause = var() 회피 패턴 적용
• FAIL → .axis-field rule 자체 또는 -- BEM modifier가 root cause

v0.1.433 — v0.1.433 — QA-122 binary search 2차 (.axis-field rule + var token 추가)

v0.1.433 v0.1.433 — QA-122 binary search 2차 (.axis-field rule + var token 추가) zip release notes GitHub
변경
v0.1.432 (:focus rule PASS) 위에 추가:
• tokens.uss: --axis-{x,y,z}-color 3 토큰 복원
• components.uss: .axis-field 절 + .axis-field--{x,y,z} .axis-field__label var() 사용
자율 검증
빌드 PASS → capture-unity-1920.sh → Read tool 시각 검증.
• UI 정상 → .axis-field rule + 토큰 안전 → v0.1.434 .axis-field-scrub__strip 추가
• UI 미렌더링 → 본 영역 root cause → 추가 binary search

v0.1.432 — v0.1.432 — QA-122 binary search 1차 (:focus rule 단독 추가)

v0.1.432 v0.1.432 — QA-122 binary search 1차 (:focus rule 단독 추가) zip release notes GitHub
핵심 변경
QA-122 binary search — v0.1.431 (USS 일괄 revert) 위에 USS rule 하나씩 단독 추가하여 root cause 식별.
1차 후보: `:focus` pseudo-class rule (v0.1.424 추가 영역)
components.uss 끝에 :focus rule 2 그룹 추가:
.unity-text-field:focus > .unity-base-text-field__input (child combinator + pseudo-class)
.unity-toggle:focus / .unity-button:focus / .unity-list-view:focus / .unity-slider:focus (descendant)
var() 토큰 제거
v0.1.431에서 토큰 제거됨 → 직접 RGB 값 사용 (rgb(255, 217, 115)). 토큰/var() 영역 분리 검증.
자율 검증
• 빌드 PASS 후 capture-unity-1920.sh 자율 캡처 + Read tool 시각 검증
• UI 렌더링 정상 → :focus rule 안전 (root cause 아님) → v0.1.433 .axis-field 추가
• UI 미렌더링 → :focus rule = root cause 확정 → revert + 다른 안전 패턴
영향 파일
• Assets/UI/Theme/components.uss — :focus rule 2 그룹 단독 추가

v0.1.431 — v0.1.431 — QA-122 긴급 fix (USS ApplyGlobalKeyword 예외 — 본 cap USS 일괄 revert)

v0.1.431 v0.1.431 — QA-122 긴급 fix (USS ApplyGlobalKeyword 예외 — 본 cap USS 일괄 revert) zip release notes GitHub
핵심 변경
협업자 PM(JP) QA-122 긴급 회기 보고:
• v0.1.425 정상 / v0.1.430 전체 UI 미렌더링
• root cause = USS StyleSheet 파싱 ApplyGlobalKeyword 예외 (Player.log L33~50)
• StylePropertyReader.GetValue index 범위 초과
v0.1.431 긴급 fix path
본 cap (v0.1.426~430) USS 추가 영역 일괄 revert:
tokens.uss --axis-{x,y,z}-color 3 토큰 제거
components.uss .axis-field 절 (35라인) 제거
components.uss .axis-field-scrub__strip rule 3 (v0.1.428) 제거
components.uss :focus pseudo-class rule 2 그룹 (v0.1.424) 제거
코드 영역 보존
• AxisFieldElement.cs / AxisFieldScrubElement.cs / AxisKind.cs 코드 유지 (USS rule 부재 시 라벨 색상만 미적용 — Inspector Transform 동작 정상)
• 코드 검증 후 binary search로 root cause USS rule 식별 → 안전한 rule 점진 추가
사용자 검증 시나리오
1. v0.1.431 zip 다운로드 + 실행
2. 전체 UI 렌더링 확인 (상단 메뉴바 / SNB / Inspector / 상태 표시줄)
3. Inspector Transform XYZ 입력 — 라벨 색상 없으나 기능 정상 의무
4. PASS 시 → v0.1.432+ binary search
영향 파일
• Assets/UI/Theme/tokens.uss — --axis-{x,y,z}-color 토큰 제거
• Assets/UI/Theme/components.uss — axis-field + focus outline 일괄 제거
다음 큐
• 사용자 PC v0.1.431 검증 응답
• PASS 시 v0.1.432~ root cause binary search (focus rule? axis-field? var() token?)
• FAIL 시 USS 외 영역 root cause 추적 (코드 + UXML + ProjectSettings)

v0.1.430 — v0.1.430 — critic 중간 #2/#3 fix (delegate GC + Vector3 indexer)

v0.1.430 v0.1.430 — critic 중간 #2/#3 fix (delegate GC + Vector3 indexer) zip release notes GitHub
핵심 변경
v0.1.427 critic 잔존 중간 결함 2건 처리. 본 cycle로 critic 결함 모두 종결.
중간 #2 — applyInputStyle delegate GC fix
• 옛: Action applyInputStyle = (target) => { ... }; local closure
◦ 매 AxisFieldScrubElement 생성자 호출마다 delegate 인스턴스 할당
• 신: static void ApplyInputStyle(TextField target) 메서드 추출
◦ delegate 할당 0 (인스턴스 method 호출만)
• 효과: RenderInspector 0.25s tick 마다 AxisFieldScrubElement × 3 생성 = delegate 할당 ↓ ~3 인스턴스/0.25s
중간 #3 — Bootstrap Vector3 indexer
• 옛: axisIdx == 0 ? working.x : axisIdx == 1 ? working.y : working.z 3항 연산자 체인
• 신: working[axisIdx] Vector3 indexer
• 효과: 가독성 + 미래 4번째 축 추가 시 silent 0 반환 위험 0
critic v0.1.427 잔존 결함 모두 종결
| # | 결함 | 처리 |
|---|---|---|
| 중대 1 | _value 이중 쓰기 | v0.1.428 setter 통일 |
| 중대 2 | _inspectorDragLockSince 리셋 | v0.1.428 안전망 fix |
| 중대 3 | _scheduledStyle.Pause 효과 X | v0.1.428 폐기 |
| 중대 4 | schedule attach 전 | docs 명시 (Unity attach 시 deferred) |
| 중간 1 | GetAxisColor 하드코딩 | v0.1.428 USS 토큰 통합 |
| 중간 2 | applyInputStyle delegate GC | v0.1.430 static method 추출 |
| 중간 3 | Bootstrap 3항 연산자 | v0.1.430 Vector3 indexer |
| 중간 4 | Axis enum 통합 | v0.1.429 AxisKind SSOT |
| 사소 1 | _axis dead field | v0.1.428 Axis property |
영향 파일
• Assets/Scripts/UI/AxisFieldScrubElement.cs — ApplyInputStyle static method 추출
• Assets/Scripts/Game/Factory00Bootstrap.cs L5784~5791 — Vector3 indexer
다음 큐
• 사용자 PC 검증 8 시나리오 응답 의무 (v0.1.427+428+429+430 통합)
• PASS 후 v0.1.431+ — 옛 #if false 영구 제거 (룰 binary-search-code-tracking.md)

v0.1.429 — v0.1.429 — Axis enum 통합 SSOT (Factory00.UI.AxisKind)

v0.1.429 v0.1.429 — Axis enum 통합 SSOT (Factory00.UI.AxisKind) zip release notes GitHub
핵심 변경
critic v0.1.427 중간 #4 fix — AxisFieldElement + AxisFieldScrubElement 의 nested Axis enum 중복 → 단일 Factory00.UI.AxisKind SSOT.
fix
Assets/Scripts/UI/AxisKind.cs 신규 — public enum Factory00.UI.AxisKind { X=0, Y=1, Z=2 }
AxisFieldElement — nested Axis enum 제거, AxisKind 활용
AxisFieldScrubElement — nested Axis enum 제거, AxisKind 활용. property Axis (PascalCase 외부 노출용)
Factory00Bootstrap.EditableVec3RowFactory00.UI.AxisFieldScrubElement.Axis.XFactory00.UI.AxisKind.X
향후 확장 안전
4번째 축 (W / Roll / Pitch) 추가 시 AxisKind.cs 1곳만 갱신:
• 양 모듈 자동 호환
• USS class .axis-field--{w,roll,pitch} 추가만 의무
영향 파일
• Assets/Scripts/UI/AxisKind.cs — 신규 (16라인)
• Assets/Scripts/UI/AxisFieldElement.cs — AxisAxisKind 치환
• Assets/Scripts/UI/AxisFieldScrubElement.cs — AxisAxisKind 치환 + Axis property
• Assets/Scripts/Game/Factory00Bootstrap.cs L5774 — AxisFieldScrubElement.AxisAxisKind
다음 큐
• 사용자 PC v0.1.427+428+429 검증 응답 의무
• PASS 후 v0.1.430+ — 옛 #if false 영역 영구 제거 + Inspector 외 단순 좌표 입력 위치 AxisFieldElement 치환

v0.1.428 — v0.1.428 — Task #159 P3 critic 후속 정리 (중대 1+3+#2 fix + 사소 정리)

v0.1.428 v0.1.428 — Task #159 P3 critic 후속 정리 (중대 1+3+#2 fix + 사소 정리) zip release notes GitHub
핵심 변경
v0.1.427 critic CONDITIONAL 후속 정리 — 중대 4건 중 3건 + 사소 fix.
critic 중대 fix
#1 _value 이중 쓰기 → setter 경유 통일 (캡슐화 보강)
PointerMoveEvent drag-scrub: _value = newValue + _tf.SetValueWithoutNotifythis.value = newValue
◦ 향후 setter 안 범위 clamp / 단위 변환 추가 시 drag-scrub 경로도 자동 적용
#2 _inspectorDragLockSince locked=false 시 리셋 (v0.1.427 코드 fix, v0.1.428 빌드 반영)
_inspectorDragLockSince = locked ? Time.time : 0f (안전망)
#3 _scheduledStyle.Pause() 폐기 (효과 없음 - ExecuteLater(0) 일회성)
◦ GC 누적 방지는 GeometryChangedEvent 핸들러가 담당
critic 중간 fix
#1 GetAxisColor 토큰 SSOT 통합
◦ 옛: new Color(0.95f, 0.35f, 0.40f, 1f) 하드코딩
◦ 신: .axis-field--{x,y,z} .axis-field-scrub__strip USS class → --axis-{x,y,z}-color 토큰
◦ components.uss 3 라인 추가
critic 사소 fix
#1 _axis dead field → public AxisKind property 노출 (외부 grep/디버깅)
잔존 (v0.1.429+)
• 중대 #4 schedule attach 전 호출 → Unity attach 시 deferred = 회귀 0 = docs 명시만
• 중간 #2 applyInputStyle local Action delegate GC → method 추출 (자율 영역)
• 중간 #3 Bootstrap for loop 3항 연산자 → Vector3 indexer (옵션)
• 중간 #4 Axis enum 통합 (AxisFieldElement vs AxisFieldScrubElement) → namespace 공유 enum
영향 파일
• Assets/Scripts/UI/AxisFieldScrubElement.cs — 중대 #1/#3 fix + 사소 #1 AxisKind property + GetAxisColor 제거
• Assets/UI/Theme/components.uss — .axis-field-scrub__strip USS class 3 라인 추가
• Assets/Scripts/Game/Factory00Bootstrap.cs — _inspectorDragLockSince fix (v0.1.427에 코드만 반영, 본 빌드에 포함)
다음 큐
사용자 PC v0.1.427+428 검증 8 시나리오 PASS 응답 → P3-c 완료 → 옛 #if false 영구 제거 (v0.1.429).

v0.1.427 — v0.1.427 — Task #159 P3 Inspector Transform scrubber 모듈화 (AxisFieldScrubElement)

v0.1.427 v0.1.427 — Task #159 P3 Inspector Transform scrubber 모듈화 (AxisFieldScrubElement) zip release notes GitHub
핵심 변경
사용자 명시 (2026-05-26): "p3 진입"
P3-a 신설
Assets/Scripts/UI/AxisFieldScrubElement.cs 신규 ~270라인
• EditableVec3Row 5 회기 fix 패턴 모두 1:1 이식:
◦ v0.1.132 Unreal 스타일 (3등분 / 왼쪽 정렬 / 컬러 strip)
◦ v0.1.165 dragLock (drag 중 closure invalidation 차단) → OnDragLockChanged 콜백
◦ v0.1.166 inner-input pickingMode=Ignore default
◦ v0.1.167 typingMode flag + originalValueBeforeFocus + frame-delayed CapturePointer (critic 중대 4 fix)
◦ v0.1.136 DetachFromPanel scheduledStyle.Pause (GC 누적 차단)
P3-b Bootstrap 치환
Factory00Bootstrap.RenderInspector.EditableVec3Row 단순화 — 옛 MakeDraggableAxisField 함수 (~200라인 local function) → AxisFieldScrubElement 모듈 3개 호출 (~25라인)
• 옛 코드 #if false 마크 (룰 binary-search-code-tracking.md — v0.1.428 + 사용자 PASS 후 영구 제거 예정)
_inspectorDragLock + _inspectorDragLockSince setter 콜백 wiring 유지
회기 차단 6항 보존
본 모듈에 다음 정밀 race fix 패턴 모두 보존:
1. OnDragLockChanged → _inspectorDragLock = true (외부 closure invalidation 차단)
2. inner-input pickingMode Ignore default
3. typingMode flag (focus 직후 GeometryChanged race 차단)
4. originalValueBeforeFocus (ESC 복원 SSOT)
5. schedule.Execute(0) frame-delayed CapturePointer (TrickleDown 라우팅 충돌 회피)
6. DetachFromPanelEvent scheduledStyle.Pause (schedule GC 누적 차단)
사용자 검증 시나리오 (8건 — pre-check.md SSOT)
1. XYZ 라벨 위 drag dx>4px → scrub 모드 + value 갱신
2. TextField click (drag <4px) → focus → 키보드 입력
3. click → 숫자 입력 → Enter → commit + Blur
4. click → 숫자 입력 → ESC → originalValueBeforeFocus 복원 + Blur
5. Shift+drag → sens 0.1 → 0.01 (정밀)
6. RenderInspector 재호출 중 drag → _inspectorDragLock=true → closure 보존
7. scrub 후 Ctrl+Z → TransformCommand Undo + 회전 복원 (v0.1.418)
8. drag 중 cursor 외부 → cursorInside 가드 (v0.1.423)
영향 파일
• Assets/Scripts/UI/AxisFieldScrubElement.cs — 신규 ~270라인
• Assets/Scripts/Game/Factory00Bootstrap.cs L5773~ — EditableVec3Row 단순화 (~25라인 신규 + ~200라인 #if false)
다음 큐
• 사용자 PC 검증 8 시나리오 PASS/FAIL 응답 의무
• PASS 후 v0.1.428 — #if false 옛 코드 영구 제거 + Bootstrap 다른 단순 좌표 입력 위치 (Sensor / Modbus) AxisFieldElement 치환 (P2)

v0.1.426 — v0.1.426 — AxisFieldElement + Vector3FieldElement (좌표/회전 통합 모듈 P1)

v0.1.426 v0.1.426 — AxisFieldElement + Vector3FieldElement (좌표/회전 통합 모듈 P1) zip release notes GitHub
핵심 변경
사용자 명시 (2026-05-26)
"모든 좌표 및 회전값에 대한 조작은 객체지향적으로 같은 모듈화된 함수를 사용하자. 디자인은 프로퍼티 좌표 표기처럼 컬러가 들어간 게 좋다"
P1 신설 (scope: scrubber-less 단순 입력 전용)
AxisFieldElement (단일 float 입력 + 컬러 라벨)
• Axis enum (X/Y/Z) + AxisToUssClass 명시 switch (enum 확장 안전)
• value getter/setter + SetValueWithoutNotify (Drag/Undo 외부 갱신용)
• OnValueChanged 이벤트 — commit 시점에만 발화 (Bootstrap.EditableVec3Row L5588 패턴 미러)
• BlurEvent + KeyDownEvent (Enter/KeypadEnter) commit 패턴
• float.TryParse — Culture 호환 (CurrentCulture, Bootstrap 정합)
Vector3FieldElement (3 AxisField 묶음)
• X/Y/Z 자식 → 전체 Vector3 통합
• OnValueChanged(Vector3) 이벤트
USS 토큰 + 스타일
--axis-x-color rgba(220,80,80,0.85) — CAD 빨강
--axis-y-color rgba(80,180,80,0.85) — CAD 초록
--axis-z-color rgba(80,110,240,0.85) — CAD 파랑
.axis-field--{x,y,z} .axis-field__label 컬러 라벨 적용
critic CONDITIONAL → 즉시 fix (중대 3 → 0)
1. isDelayed + RegisterValueChangedCallback blur race → BlurEvent + KeyDownEvent 패턴 (Bootstrap 미러)
2. scrubber 누락 → P1 scope = scrubber-less 명시 (Inspector Transform P3 별도)
3. Culture 차이 → NumberStyles 제거 (Bootstrap CurrentCulture 정합)
추가 처리 (중간/사소):
• USS 색상 hardcoded → tokens.uss SSOT 추출
• Axis enum → switch 명시 (확장 안전)
• FocusInput 미사용 API 제거
• v0.1.424 주석 → v0.1.426 정정
P1 사용처 (P2 대상)
Inspector Transform 외 일반 좌표/회전 입력 영역:
• Modbus Mapping XYZ
• Sensor 속성 (PhotoSensor angle / SensingDistance 등)
• Servo 속성 (HomePosition 등)
• ContextMenu 좌표 다이얼로그 (향후)
Inspector Transform 자체는 P3 scrubber-aware 파생 클래스로 별도 처리 (v0.1.167 drag-scrub 회귀 차단).
영향 파일
• Assets/Scripts/UI/AxisFieldElement.cs — 신규 (~190라인)
• Assets/UI/Theme/tokens.uss — --axis-{x,y,z}-color 3 토큰 신규
• Assets/UI/Theme/components.uss — .axis-field 절 신규 (~35라인)
다음 자율 큐
P2 — Modbus Mapping / Sensor / Servo 속성에서 기존 SensorFloatField → AxisFieldElement 치환.
P3 — Inspector Transform scrubber-aware AxisFieldScrubElement 파생 클래스.

v0.1.425 — v0.1.425 — Application.isFocused 가드 (Win32 background 안전망)

v0.1.425 v0.1.425 — Application.isFocused 가드 (Win32 background 안전망) zip release notes GitHub
핵심 변경
CameraViewController.Update 안 isFocused 가드 추가
Win32 표준: background window 는 input 자체 OS 차단. Unity Input.* 도 background 시 안 발화. 하지만 stale state 회피 + 명시 안전망으로 가드 추가.
`csharp
void Update()
{
if (!Application.isFocused) return; // v0.1.425
bool textFocused = TextFocused();
...
}
`
적용 안 함 (의도)
• Bootstrap.Update 안 단일 키 핸들러 (M/T/B/L/X 등) 별도 가드 안 함
• 이유: Windows 자연 차단 (background = WM_KEYDOWN 안 옴). redundancy 회피
• 그러나 CameraViewController 는 mouse stale value 처리 필요 → 명시 가드 적용
Win32 표준 정합 누적 (v0.1.420~425)
| 버전 | 보강 |
|---|---|
| v0.1.420 | IsAnyUIFocused 헬퍼 (모든 UI focus 상태 catch) |
| v0.1.421 | 3D click 시 UI focus blur |
| v0.1.422 | UpdateOrbit/UpdateFirstPerson early return 제거 (마우스 활성) + ESC blur |
| v0.1.423 | cursor 외부 마우스 차단 (cursorInside 가드) + ESC cascade 1개씩 (else if) |
| v0.1.424 | 단일 키 IsAnyUIFocused 가드 (M/T/B/L/X) + USS focus outline |
| v0.1.425 | Application.isFocused 가드 (background 안전망) |
영향 파일
• Assets/Scripts/Game/CameraViewController.cs L192~ — Update isFocused 가드
검증 시나리오 (사용자 PC)
1. 빌드 실행 → Alt+Tab 다른 앱 활성 → 마우스 이동 = 카메라 회전 0 PASS 의무
2. 빌드 minimize → 복귀 → 정상 동작 PASS 의무
다음 자율 큐
Task #159 좌표/회전 모듈 P1 — AxisFieldElement 신설 (단일 float 입력 + X/Y/Z 컬러).

v0.1.424 — v0.1.424 — 단일 키 IsAnyUIFocused 가드 + USS focus outline

v0.1.424 v0.1.424 — 단일 키 IsAnyUIFocused 가드 + USS focus outline zip release notes GitHub
핵심 변경
단일 글자 키 핸들러 5개 가드 강화
포커스 기조 룰 적용 — 단일 알파벳 키는 UI focus 시 차단 의무.
| 키 | 동작 | 옛 가드 | v0.1.424 |
|---|---|---|---|
| M | ContextMenu (마우스 fallback) | IsAnyTextFieldFocused | IsAnyUIFocused |
| T | 부품 트리 focus | IsAnyTextFieldFocused | IsAnyUIFocused |
| B | BBox outline toggle | IsAnyTextFieldFocused | IsAnyUIFocused |
| L | Lit toggle | IsAnyTextFieldFocused | IsAnyUIFocused |
| X | Gizmo space toggle (World/Local) | IsAnyTextFieldFocused | IsAnyUIFocused |
옛 IsAnyTextFieldFocused 유지 영역 (의도):
/ 검색 focus (TextField 안 / 입력 가능)
• Delete (TextField 안 텍스트 삭제 가능)
• F10 / ? / Help (Function 키 또는 modifier)
• 마우스 button (cursor 외부 가드 별개)
USS focus outline 추가
컴포넌트별 :focus pseudo-class — *:focus 전역 회피 (잡음 방지):
unity-text-field:focus > input — 골드 1px border
unity-button:focus — 골드 1px border
unity-toggle:focus — 골드 1px border
unity-list-view:focus — 골드 1px border
unity-slider:focus — 골드 1px border
토큰 --gold-edge-strong (rgb 255,217,115, alpha 0.75) 활용.
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L4277/4402/4425/4430/4472 — M/T/B/L/X IsAnyUIFocused
• Assets/UI/Theme/components.uss 끝 — 컴포넌트별 focus outline 5종 추가
검증 시나리오 (사용자 PC)
1. Inspector TextField focus → M 키 = 차단 PASS 의무 (옛 활성)
2. 메뉴바 button focus → B 키 = 차단 PASS 의무 (옛 활성)
3. 3D click → focus blur → M 키 = ContextMenu 활성 PASS
4. TextField click 시 외곽선 골드 1px 표시 PASS 의무
5. Button focus (TAB navigation) 시 외곽선 골드 1px 표시 PASS 의무
다음 자율 큐
Application.isFocused 가드 추가 (cursor 외부 별개) + Task #159 좌표 모듈 시작.

v0.1.423 — v0.1.423 — cursor 외부 마우스 차단 + ESC cascade 1개씩 (Win32 표준 보강)

v0.1.423 v0.1.423 — cursor 외부 마우스 차단 + ESC cascade 1개씩 (Win32 표준 보강) zip release notes GitHub
핵심 변경
사용자 명시 (2026-05-26)
1. ESC = "한 개씩 닫기" — cascade 1단계씩만 처리
2. "마우스 커서가 우리 프로그램 외부에 있을 경우 우리 프로그램 활성화 여부와 관계없이 마우스 입력도 막혀야한다"
3. "윈도우 프로그래밍 관련 서적이나 지식 검색하여 관련 내용 보강"
fix
CameraViewController.UpdateOrbit/UpdateFirstPerson/UpdateOrthocursorInside 가드 추가
◦ RMB 회전 / wheel 줌 / MMB pan / FP 마우스 시선 모두 cursorInside && 가드
Input.mousePosition Screen.width/height 범위 검증
Bootstrap.Update ESC handler cascade if + handledelse if 정리
◦ 한 번 ESC = 한 단계만. 재차 ESC = 다음 단계
• 룰 focus-key-isolation.md 보강 — Win32 표준 입력 패턴 표 + Charles Petzold/Raymond Chen 참조
Win32 표준 vs factory00 정합
| 입력 | Windows 표준 | factory00 적용 |
|---|---|---|
| ESC | cascade 1개씩 닫기 | v0.1.423+ |
| TAB / Enter / Space | UI Toolkit 자동 처리 | 유지 |
| F1~F12 | 전역 단축키 | 유지 |
| Alt+글자 | mnemonic | 유지 |
| Ctrl+조합 | 표준 단축키 | 유지 |
| 단일 글자 | TextField focus 시 차단 | v0.1.420+ |
| 마우스 cursor 외부 | client area 안만 입력 | v0.1.423+ cursorInside 가드 |
Win32 vs 사용자 의도 trade-off
| 시나리오 | Win32 SetCapture default | factory00 (사용자 명시) |
|---|---|---|
| drag 시작 후 cursor 외부 | 회전 계속 | 차단 (사용자 명시 우선) |
| drag 시작 시점 cursor 외부 | 시작 불가 | 차단 |
| cursor 외부 wheel | wheel 안 발화 | 차단 안전망 |
영향 파일
• Assets/Scripts/Game/CameraViewController.cs L378~ + L516~ + L535~ — cursorInside 3 위치
• Assets/Scripts/Game/Factory00Bootstrap.cs L4243~ — ESC cascade else if
• .claude/rules/focus-key-isolation.md — Windows 표준 입력 패턴 표 + cursorInside 절 + ESC cascade 절 + 참고 자료
검증 시나리오 (사용자 PC)
1. 카메라 RMB drag 중 cursor 를 프로그램 외부로 → 회전 중단 PASS 의무
2. cursor 외부에서 wheel 굴림 → 줌 0 PASS 의무
3. TextField focus → ESC → focus 해제 (선택 유지) → ESC 다시 → 선택 해제 PASS 의무
4. ContextMenu 열림 → ESC → 메뉴만 닫힘 (선택/focus 유지) PASS 의무
다음 자율 큐
USS focus outline (컴포넌트별 — 모든 element *:focus 회피) + 단일 키 핸들러 (G/U/M/F/H 등) 추가 가드.

v0.1.422 — v0.1.422 — 포커스 기조 취약점 3건 보강 (마우스 항상 활성 + ESC blur)

v0.1.422 v0.1.422 — 포커스 기조 취약점 3건 보강 (마우스 항상 활성 + ESC blur) zip release notes GitHub
핵심 변경
취약점 검토 결과 (사용자 명시 2026-05-26)
v0.1.420 IsAnyUIFocused 도입 + v0.1.421 3D click blur 후 잠재 취약점 3건 식별:
1. UpdateOrbit early return = 마우스 차단 (24-redesign-16 자체 측 textFocused 일괄 차단 패턴)
2. UpdateFirstPerson early return = 마우스 시선 차단
3. ESC 키 → UI focus 해제 path 부재 (전통 Windows 표준 미준수)
fix
CameraViewController.UpdateOrbit early return 제거 — 마우스 RMB 회전 / wheel 줌 / MMB pan 항상 활성. 키보드 fly wasd/qe 영역은 L452 textFocused 가드 유지
CameraViewController.UpdateFirstPerson early return 제거 — 마우스 시선 회전 항상 활성. 키보드 wasd/qe/Space/C 영역만 L543 textFocused 가드
Bootstrap.Update ESC handler 안 cascade 4단계 추가 — UI focus 있음 시 focusedElement.Blur() 호출 (ContextMenu/dragSelect/subWindow 닫힘 후 / 선택 해제 직전)
• 룰 focus-key-isolation.md 보강 — "마우스는 차단 대상 X" + "ESC = UI focus 명시 해제" 두 절 신규
사용자 의도 vs 자체 측 옛 패턴
| 입력 | 사용자 의도 | 자체 측 옛 패턴 | v0.1.422 fix |
|---|---|---|---|
| 키보드 단일 키 (wasd 등) | TextField focus 시 차단 | textFocused 가드 (이미 OK) | 유지 |
| Function 키 / Ctrl+키 / Alt+키 | 항상 활성 (전역) | 가드 X (이미 OK) | 유지 |
| 마우스 RMB 회전 | 항상 활성 | textFocused early return 차단 | early return 제거 |
| 마우스 wheel 줌 | 항상 활성 | textFocused early return 차단 | early return 제거 |
| 1인칭 마우스 시선 | 항상 활성 | textFocused early return 차단 | early return 제거 |
| ESC | UI focus 해제 후 cancel cascade | focus blur path 부재 | cascade 4단계 신규 |
영향 파일
• Assets/Scripts/Game/CameraViewController.cs L382, L529 — early return 제거
• Assets/Scripts/Game/Factory00Bootstrap.cs L4243~ — ESC handler cascade 4단계 추가
• .claude/rules/focus-key-isolation.md — "마우스 차단 X" + "ESC blur" 두 절 신규
검증 시나리오 (사용자 PC)
1. Inspector 좌표 TextField click → focus → 마우스 휠 = 카메라 줌 PASS 의무 (옛 차단)
2. Inspector 좌표 TextField click → focus → RMB 회전 = 카메라 회전 PASS 의무
3. 1인칭 모드 + Inspector focus → 마우스 시선 = 회전 PASS 의무
4. TextField focus 후 ESC = focus 해제 → 다시 ESC = 선택 해제
다음 자율 큐
USS *:focus outline + 단일 키 핸들러 (G/U/M/F/H 등) 추가 IsAnyUIFocused 가드.

v0.1.421 — v0.1.421 — 3D click 시 UI focus blur (포커스 기조 보강)

v0.1.421 v0.1.421 — 3D click 시 UI focus blur (포커스 기조 보강) zip release notes GitHub
핵심 변경
사용자 명시 보강 (2026-05-26)
• "단순 wasd만 해당하는 것이 아님, a-z 모든 알파벳 / 숫자 / 특수문자 / 방향키 포함"
• "3d영역 클릭 시 3d영역에 대한 조작 (wasd f g 등) 활성화"
자체 측 fix
• Update L4116~4127 안 3D click handler — focusedElement.Blur() 호출 추가
• UI element (TextField/Button/메뉴바) focus 후 3D click 시 명시 UI blur → IsAnyUIFocused = false → 단일 키 자동 활성
• 룰 보강 — focus-key-isolation.md "3D viewport 포커스 개념" 절 추가
v0.1.420 + v0.1.421 통합 동작
| 사용자 동작 | UI focus | 단일 키 효과 |
|---|---|---|
| TextField click | TextField focus | wasd 차단 (텍스트 입력) |
| 메뉴바 click | 메뉴 focus | wasd 차단 |
| 3D viewport click | UI focus 해제 | wasd 활성 (카메라 이동) |
| Function 키 / Ctrl+키 / Alt+키 | 무관 | 모든 영역 활성 (전역 단축키) |
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs Update L4116~4127 — 3D click 시 focusedElement.Blur()
• .claude/rules/focus-key-isolation.md — 3D viewport 포커스 개념 절 추가
다음 자율 큐
USS *:focus outline + 단일 키 핸들러 (G/U/M/F/H 등) 추가 가드 → Task #159 좌표 모듈화.

v0.1.420 — v0.1.420 — 포커스 기조 룰 영구화 + IsAnyUIFocused 헬퍼 (사용자 명시)

v0.1.420 v0.1.420 — 포커스 기조 룰 영구화 + IsAnyUIFocused 헬퍼 (사용자 명시) zip release notes GitHub
핵심 변경
포커스 기조 룰 (사용자 명시 2026-05-26)
• 모든 UI element focusable + focus outline 표시 (프로퍼티 영역 패턴)
• 포커스 영역별 단일 알파벳/숫자 키 입력 독립
◦ 텍스트필드 / 메뉴바 / Button / ListView 포커스 시 wasd 카메라 이동 X
◦ Function / Ctrl 조합 / Alt 조합 = 예외 (계속 작동)
• 전통 Windows 표준
자체 측 fix
IsAnyUIFocused() 신규 헬퍼 — 모든 focusable element 포커스 검증 (TextField 외 Button/ListView 포함)
• CameraViewController.IsTextInputFocused 콜백 = IsAnyUIFocused() 변경 — UpdateOrbit / UpdateFirstPerson 안 WASD/QE/SC 자동 차단
룰 영구화
.claude/rules/focus-key-isolation.md 신설 (워크스페이스 전역)
잔존 사이클 작업
| 영역 | 사이클 |
|---|---|
| USS *:focus outline 추가 | 별도 cycle (디자인) |
| 단일 키 핸들러 (G/U/M/F/H 등) 추가 가드 | 별도 cycle |
| 메뉴바 (tab-file 등) focusable 명시 | 별도 cycle |
| Task #159 좌표/회전 모듈화 | 별도 cycle |
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L468~485 — IsAnyUIFocused 신규 헬퍼
• Assets/Scripts/Game/Factory00Bootstrap.cs L399 — IsTextInputFocused 콜백 변경
• .claude/rules/focus-key-isolation.md 신설
다음 자율 큐
USS focus outline + 단일 키 가드 전수 추가 → 좌표/회전 모듈화 (Task #159).

v0.1.419 — v0.1.419 — QA-081 카메라 모델 소멸 fix (Camera near/far clipping plane mm scaled 정합)

v0.1.419 v0.1.419 — QA-081 카메라 모델 소멸 fix (Camera near/far clipping plane mm scaled 정합) zip release notes GitHub
핵심 변경
QA-081 잔존 fix — 카메라 이동 시 모델 소멸
• 사용자 보고: "카메라 이동 시 모델 소멸 간헐 발생"
• root cause: Unity Camera default near 0.3 / far 1000 = 0.3mm / 1m 영역. factory00 mm scaled Transform 정합 안 됨.
◦ near 0.3mm: 사용자 카메라 모델 가까이 접근 시 0.3mm 이내로 들어가면 near clip → 모델 사라짐
◦ far 1000 (1m = 1000 unit): 모델 8800mm 크기 + 카메라 거리 = far 너머 → 모델 사라짐
• fix: CameraViewController.Awake 안 명시 설정
◦ cam.nearClipPlane = 1f (1mm)
◦ cam.farClipPlane = 1000000f (1km = 1,000,000mm)
Group E QA-081 100% 완료
| 영역 | fix 빌드 |
|---|---|
| WASD 이동 | v0.1.397 |
| Space / C 키 (위/아래) | v0.1.397 |
| BBox LookAt fallback | v0.1.397 |
| 이동 속도 1000배 (mm 스케일) | v0.1.412 |
| 크로스헤어 위치 | v0.1.417 |
| 카메라 이동 시 모델 소멸 | v0.1.419 |
영향 파일
• Assets/Scripts/Game/CameraViewController.cs Awake — nearClipPlane 1f + farClipPlane 1,000,000f
다음 자율 큐
사용자 추가 검증 응답 → 잔존 fix 큐 (QA-014 6차 / QA-106 검증).

v0.1.418 — v0.1.418 — Rotate UndoStack signature 확장 (TransformCommand rotation 추가)

v0.1.418 v0.1.418 — Rotate UndoStack signature 확장 (TransformCommand rotation 추가) zip release notes GitHub
핵심 변경
Rotate Undo fix (사용자 보고 v0.1.410: "Ctrl+Z 회전 Undo 안 된다")
| 영역 | 기존 | v0.1.418 |
|---|---|---|
| TransformCommand 필드 | List beforePos / afterPos | + List beforeRot / afterRot |
| Execute / Undo | position만 적용 | position + rotation 양쪽 적용 |
| RuntimeGizmo OnDragEnded signature | Action | Action |
| EndDrag changed 검증 | position diff만 | position OR rotation diff |
| Bootstrap subscriber | TransformCommand(targets, before, after) | + beforeRot/afterRot wrap |
Description "이동" vs "회전" 분기
beforePos == null + beforeRot != null = Rotate 모드 → Description "회전: ..."
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs TransformCommand class — rotation 필드 + Execute/Undo 확장
• Assets/Scripts/Game/Factory00Bootstrap.cs OnDragEnded subscriber — 5인자 signature
• Assets/Scripts/Game/RuntimeGizmo.cs OnDragEnded signature — 5인자 확장
• Assets/Scripts/Game/RuntimeGizmo.cs EndDrag — rotation 변경 검증 추가
다음 자율 큐
사용자 추가 검증 응답 → 카메라 이동 시 모델 소멸 (near/far clipping).

v0.1.417 — v0.1.417 — 크로스헤어 위치 동적 좌표 (3D viewport 중앙)

v0.1.417 v0.1.417 — 크로스헤어 위치 동적 좌표 (3D viewport 중앙) zip release notes GitHub
핵심 변경
크로스헤어 위치 fix
• 사용자 보고 (v0.1.397 시점): "크로스헤어가 3D 영역 중앙에 있어야 하는데 전체 창의 중앙에 있다"
• root cause: UXML L148 crosshair root 자식 + USS top/left 50% = 전체 창 중앙 (좌측 패널 + ribbon 포함 → 시각 중앙 우측 치우침)
• fix: Bootstrap.Update 안 1인칭 모드일 때 매 frame leftPanel.width + ribbon.height 보정 후 viewport 중앙 좌표 갱신
◦ left = leftPanelW + viewportW × 0.5 - 12
◦ top = ribbonH + viewportH × 0.5 - 12
• 사용자 resize / mode 전환 시 자동 추종
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs Update — 1인칭 모드 시 crosshair 위치 동적 갱신 (GetViewportBounds 활용)
사용자 v0.1.397~410 영역
| 영역 | 빌드 |
|---|---|
| WASD/Space/C | v0.1.397 |
| BBox LookAt fallback | v0.1.397 |
| fpSpeed 1000배 (mm 스케일) | v0.1.412 |
| 크로스헤어 위치 3D viewport 중앙 | v0.1.417 |
다음 자율 큐
Rotate UndoStack signature 확장 → 사용자 추가 검증 응답.

v0.1.416 — v0.1.416 — Ctrl+X 후 click 차단 fix (CutSelected state reset)

v0.1.416 v0.1.416 — Ctrl+X 후 click 차단 fix (CutSelected state reset) zip release notes GitHub
핵심 변경
Ctrl+X 후 다른 오브젝트 click 차단 fix
• 사용자 보고 (v0.1.410): "잘라내기 후 다른 오브젝트 클릭이 불가능해진다. 트리에서 다른 오브젝트를 클릭하면 정상"
• root cause: CutSelected → DeleteSelectedPart 후 3D click handler state (_isDragSelecting / _lmbDownPos / _lmbDownFrame / _inspectorDragLock) 잔존 → 후속 3D click 차단
• fix: CutSelected 끝에 명시 state reset 4개 추가
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs CutSelected (L2604~) — state reset 4건 추가
다음 자율 큐
crosshair 위치 동적 → Rotate UndoStack signature 확장 → 사용자 추가 검증 응답.

v0.1.415 — v0.1.415 — QA-117 dedup 최적화 + 우클릭 메뉴 Y 반전 + drag 외곽선 갱신

v0.1.415 v0.1.415 — QA-117 dedup 최적화 + 우클릭 메뉴 Y 반전 + drag 외곽선 갱신 zip release notes GitHub
핵심 변경 (사용자 보고 3건 통합)
1. QA-117 dedup HashSet 최적화 (8000개+ click 렉 fix)
• 사용자 보고: "부품 트리 모두 펼치기 하면 오브젝트 누를 때마다 렉 2초씩 걸린다"
• root cause: UpdateGizmoTargets dedup IsChildOf O(N²) — 8000개 부품 root click 시 64M operation
• fix: parent transform HashSet 캐시 → O(N × depth) ≈ 80K operation (1000배+ 성능)
2. 우클릭 메뉴 위치 Y 반전 fix
• 사용자 보고: "우클릭 메뉴가 클릭한 위치에 떠야 하는데 엉뚱한 곳에 출력"
• root cause: Unity Input.mousePosition Y = 좌하단 origin, UI Toolkit panel = 좌상단 origin
• fix: ShowContextMenuAtMouse에서 new Vector2(x, Screen.height - y) 명시 Y 반전
3. drag 중 외곽선 갱신
• 사용자 보고: "드래그 중 외곽선이 같이 안 움직인다. 기즈모와 오브젝트, 외곽선 세가지는 같이 움직이도록"
• root cause: OnDragEnded만 HighlightSelectedParts 호출 → drag 종료 시점만 갱신
• fix: Update 안 _gizmo.DraggingAxis >= 0 시 매 frame HighlightSelectedParts 호출
별도 사이클 영역
Rotate UndoStack: TransformCommand signature 확장 의무 (position + rotation) — 큰 변경
Ctrl+X 후 click: root cause 추가 진단 필요
crosshair 위치: viewport 영역 동적 좌표 계산
QA-014 6차: 사용자 Player.log 분석 후 정밀 fix
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs UpdateGizmoTargets — HashSet dedup
• Assets/Scripts/Game/Factory00Bootstrap.cs ShowContextMenuAtMouse — Y 반전
• Assets/Scripts/Game/Factory00Bootstrap.cs Update — drag 중 outline 갱신
다음 자율 큐
QA-014 Player.log 분석 → Rotate UndoStack signature 확장 → Ctrl+X click 차단 진단.

v0.1.414 — v0.1.414 — QA-097 6차 fix (viewport 좌표 검증) + QA-014 5차 진단

v0.1.414 v0.1.414 — QA-097 6차 fix (viewport 좌표 검증) + QA-014 5차 진단 zip release notes GitHub
핵심 변경
QA-097 6차 fix (사용자 보고 v0.1.410 잔존)
• 사용자 보고: "메뉴바 서브창 씬 click 시 미닫힘 — 410에서도 미수정"
• root cause: v0.1.387 51st seal REAL FIX에서 L4067 if (!overUI && _lnbActiveIdx >= 0) HideLnbDropdown() 주석 처리 (QA-104 회기 fix). QA-097은 잔존.
• fix: inViewport && _lnbActiveIdx >= 0 조건으로 변경
◦ 3D viewport click = inViewport=true → HideLnbDropdown (QA-097 PASS)
◦ LNB dropdown click = inViewport=false (좌측 패널 영역) → HideLnbDropdown skip (QA-104 fix 보존)
QA-014 5차 진단 (v0.1.413)
• SetPresetView 안 LogWarning 추가 (사용자 Player.log 분석 의무)
QA-097 + QA-104 동시 PASS 가능 (trade-off 해소)
| 시점 | L4067 | QA-097 | QA-104 |
|---|---|---|---|
| v0.1.332 | if (!overUI...) | PASS | FAIL (회기) |
| v0.1.387 REAL FIX | 주석 처리 | FAIL | PASS |
| v0.1.414 | if (inViewport...) | PASS | PASS |
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L4067 — viewport 좌표 검증 path
다음 자율 큐
QA-014 v0.1.413 Player.log 분석 → v0.1.414 PASS 검증 → drag 외곽선 + Rotate Undo + Ctrl+X.

v0.1.413 — v0.1.413 — QA-014 5차 진단 (LogWarning) + New UI PASS

v0.1.413 v0.1.413 — QA-014 5차 진단 (LogWarning) + New UI PASS zip release notes GitHub
핵심 변경
QA-014 5차 진단 로그
• 사용자 보고 (v0.1.410 5차 시도 실패): "여전히 토스트 만 출현하고 카메라는 아무런 변화가 없다"
• SetPresetView 안 LogWarning 추가 — yaw/pitch/_mode/cam.name/target.name/_boundsCenter/orbitDistance/cam.position before/after/orthographic 진단
• 사용자 PC Player.log 첨부 요청 의무
v0.1.410 사용자 PASS (New UI 갱신)
• "새 프로젝트 눌렀을 때 3D 영역의 기즈모/선택 박스/Inspector/모터 창 갱신" PASS
QA-014 fix 누적 시도 (5차)
| 빌드 | fix | 결과 |
|---|---|---|
| v0.1.391 | ApplyMode Default target null fallback | FAIL |
| v0.1.398 | ApplyPresetCameraPosition SSOT 호출 | FAIL |
| v0.1.407 | SetPresetView FirstPerson 가드 제거 | FAIL |
| v0.1.410 | SetPresetView _orbitPanOffset reset | FAIL |
| v0.1.413 | LogWarning 진단 추가 | 사용자 Player.log 분석 후 fix |
사용자 PC Player.log 분석 요청
뷰 메뉴 정면 click 후 다음 정보 확인:
• _mode = ? (FirstPerson이면 다른 분기 의심)
• cam = ? (NULL이면 GetCam 부재)
• target = ? (null이면 _boundsCenter fallback path)
• _boundsCenter = ? (zero면 AutoFit 미호출)
• orbitDistance = ? (0이면 cam 위치 변화 없음)
• cam.pos before/after = ? (동일하면 cam.transform 갱신 안 됨)
• ortho = ? (true면 orthographicSize 영향)
영향 파일
• Assets/Scripts/Game/CameraViewController.cs L608~618 — SetPresetView LogWarning 진단
다음 자율 큐
사용자 Player.log 첨부 → v0.1.413 진단 분석 → 진짜 root cause + 6차 fix.

v0.1.412 — v0.1.412 — QA-106 v0.1.395 재탈락 fix + QA-081 1인칭 속도 + STD-0003 (사용자 보고 통합)

v0.1.412 v0.1.412 — QA-106 v0.1.395 재탈락 fix + QA-081 1인칭 속도 + STD-0003 (사용자 보고 통합) zip release notes GitHub
핵심 변경
QA-106 Inspector 텍스트필드 root callback fix (사용자 보고)
• v0.1.395 (_detailPane RegisterCallback) → TextField 내부 StopPropagation 또는 event target 불일치로 callback 안 도달 가능성
• EnsureRootInspectorCallbacks 신설: uiDocument.rootVisualElement에 PointerDown/MouseDown/KeyDown/FocusIn 등록 + event.target 자체가 _detailPane 자손이면 grace timer 시작
• INSPECTOR_INTERACTION_GRACE 1.5s → 5.0s 확장
QA-081 1인칭 이동 속도 fix (사용자 보고)
• fpSpeed default 2f → 2000f (factory00 mm scaled Transform 정합)
• 사용자 보고: "이동 속도가 너무 느려서 분 단위로 누르고 있으면 이동이 미세하게 보임"
• 잔존: 크로스헤어 위치 (3D 영역 중앙 ≠ 전체 창 중앙) 별도 사이클
STD-0003 정합 정정 (v0.1.411 부터)
• RuntimeGizmo sharedMaterial → material 10건
사용자 보고 history
| 시각 | 영역 | 본 빌드 처리 |
|---|---|---|
| 01:25 | QA-106 v0.1.395 재탈락 | root callback fix |
| 01:30 | QA-081 1인칭 너무 느림 + 크로스헤어 위치 | fpSpeed 1000배 + 크로스헤어 별도 |
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L492~519 — EnsureRootInspectorCallbacks 신설 + GRACE 5s + RenderInspector 호출
• Assets/Scripts/Game/CameraViewController.cs L35 — fpSpeed 2 → 2000
다음 자율 큐
크로스헤어 위치 fix (3D 영역 중앙) → QA-119 v0.1.410 검증 → Group B SNB.

v0.1.411 — v0.1.411 — STD-0003 RuntimeGizmo 정합 정정 (sharedMaterial → material 10건)

v0.1.411 v0.1.411 — STD-0003 RuntimeGizmo 정합 정정 (sharedMaterial → material 10건) zip release notes GitHub
핵심 변경
• RuntimeGizmo.cs 안 sharedMaterial → material 일괄 치환 (10건)
• 협업자 standards STD-0003 (Material Instance Policy) 정합 정정
STD-0003 정합
| 영역 | 기존 | v0.1.411 |
|---|---|---|
| L143/168/204/233 (할당) | sharedMaterial = mat | material = mat (Unity 자동 instance) |
| L487~501 (hover 색상 변경) | sharedMaterial.color = ... | material.color = ... (instance 변경) |
| L517~523 (LineRenderer 색상) | sharedMaterial.color = ... | material.color = ... |
동작 영향
자체 측 RuntimeGizmo는 1 Renderer 1 Material 패턴 (각 axis별 자체 생성). sharedMaterial / material 양쪽 모두 동일 시각 동작. STD-0003 표준 명확화만.
영향 파일
• Assets/Scripts/Game/RuntimeGizmo.cs 10건 치환
다음 자율 큐
사용자 검증 응답 → Group B SNB 트리 옵션 C → QA-086 이동/리사이즈.

v0.1.410 — v0.1.410 — QA-014 _orbitPanOffset reset + New UI 갱신 + Group A QA-110 PASS

v0.1.410 v0.1.410 — QA-014 _orbitPanOffset reset + New UI 갱신 + Group A QA-110 PASS zip release notes GitHub
핵심 변경 (사용자 보고 통합 fix)
1. QA-014 v0.1.408 잔존 fix (사용자 "여전히 동일")
• SetPresetView 안 _orbitPanOffset = Vector3.zero 명시 reset 추가
• root cause: _orbitPanOffset 사용자 pan 누적값 → ApplyPresetCameraPosition 안 cam.position = center + _orbitPanOffset + ... = BBox 멀리 이탈 → 시각 미전환
2. New 시 UI 갱신 (사용자 보고 2026-05-26 01:15)
• cmd-new 핸들러에 selection 초기화 + UI 갱신 6건 호출
• _selectedPart=null + _selectedParts.Clear() + HighlightSelectedParts + UpdateGizmoTargets + SetSelectedPart(null) + Inspector empty
Group A QA-110/111/114 100% 사용자 PASS
| QA | 빌드 | PASS |
|---|---|---|
| QA-110 (Duplicate ghost) | v0.1.405 | 2026-05-26 01:20 |
| QA-111 (deselect 잔존) | v0.1.396 | (PM 검증 대기) |
| QA-114 (Delete 잔존) | v0.1.396 | (PM 검증 대기) |
사용자 PASS 누계 (본 cap 8건)
| 시각 | 영역 | 빌드 |
|---|---|---|
| 22:55 | QA-118 옛 F-key | v0.1.390 |
| 23:00 | F5~F8 + F4 토글 | v0.1.390 |
| 23:10 | PhotoSensor 라인 | v0.1.394 |
| 00:55 | 와이어프레임 토글 F3 | v0.1.399 |
| 01:00 | 공압 Gizmo 거리 | v0.1.400 |
| 01:15 | 접기 버튼 -40px | v0.1.406 |
| 01:18 | Alt+F / Alt+H 가드 | v0.1.408 |
| 01:20 | QA-110 ghost | v0.1.405 |
영향 파일
• Assets/Scripts/Game/CameraViewController.cs L612 — _orbitPanOffset reset
• Assets/Scripts/Game/Factory00Bootstrap.cs cmd-new 핸들러 — UI 갱신 6건 호출
다음 자율 큐
v0.1.410 사용자 검증 → STD-0003 정합 → Group B SNB.

v0.1.409 — v0.1.409 — QA-119 v0.1.408 잔존 fix (캐시 재빌드 + ListView Rebuild)

v0.1.409 v0.1.409 — QA-119 v0.1.408 잔존 fix (캐시 재빌드 + ListView Rebuild) zip release notes GitHub
핵심 변경 (사용자 보고 2026-05-26 01:15)
• 사용자 보고: "부품 트리 보이지 않음 → 부품 클릭 시 갱신 + 트리의 계층이 전혀 없이 모두 root에 있음"
• root cause: OpenTwnPath에서 STEP 자동 재임포트 + parentId 덮어쓰기 + ApplyTwnPayload 호출 후 캐시 재빌드 누락:
_childrenByParentId 캐시 미갱신 → 계층 hierarchy 무시 → 모두 root 표시
RebuildVisibleParts 미호출 → ListView itemsSource stale
_partList.Rebuild() 미호출 → UI 갱신 안 됨 → 부품 click 시 lazy 갱신
• fix: ApplyTwnPayload 호출 직후 BuildPartDepthCache + BuildPartByTransformCache + RebuildVisibleParts + _partList.Rebuild() 명시 호출
v0.1.408 잔존 영역
| 영역 | 상태 |
|---|---|
| STEP 자동 재임포트 | 정상 |
| 부품 위치 복원 | 정상 |
| 계층 hierarchy 표시 | 본 fix |
| ListView 초기 갱신 | 본 fix |
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs OpenTwnPath ApplyTwnPayload 직후 — 캐시 재빌드 + ListView Rebuild 4건 호출
다음 자율 큐
사용자 PC 재검증 → STD-0003 RuntimeGizmo 정합 → Group B SNB.

v0.1.408 — v0.1.408 — Alt+F/H 단일 키 충돌 fix (사용자 보고 2026-05-26)

v0.1.408 v0.1.408 — Alt+F/H 단일 키 충돌 fix (사용자 보고 2026-05-26) zip release notes GitHub
핵심 변경 (사용자 보고 Alt+mnemonic)
Alt+F / Alt+H 충돌 fix
• 사용자 보고 (2026-05-26 01:10): "F나 H는 기존 키와 동시에 호출된다. Alt와 같이 조합 키를 사용할 때에는 단일 키는 호출되지 않아야 한다"
• root cause:
◦ F 키 단일 = Focus selected (CameraViewController L213)
◦ H 키 단일 = 도움말 토글 (Bootstrap L4318)
◦ Alt+F / Alt+H 누름 시 단일 키 가드 부재 → 동시 발화
• fix: Alt 가드 추가
◦ CameraViewController L213 F 핸들러: && !Input.GetKey(KeyCode.LeftAlt) && !Input.GetKey(KeyCode.RightAlt)
◦ Bootstrap L4316~4319 H 핸들러: 동일 가드
Alt+R NVIDIA 오버라이드 (자체 측 변경 보류)
• 사용자 보고: "Alt+R은 Nvidia 단축키가 오버라이드 한 것인지 FPS와 GPU CPU 지연시간 정보가 화면에 토글"
• 진단: GeForce Experience FPS overlay 기본 단축키 = Alt+R. 사용자 환경 의존
• 자체 측 영역 외 — 사용자 NVIDIA 단축키 비활성화 또는 향후 대체 키 사용자 명시 후 결정
사용자 PC 검증 누적 (Alt+mnemonic)
| 키 | 결과 |
|---|---|
| Alt+E (편집) | PASS |
| Alt+V (뷰) | PASS |
| Alt+C (부품) | PASS |
| Alt+T (도구) | PASS |
| Alt+F (파일) | 본 fix 후 검증 의무 |
| Alt+H (도움말) | 본 fix 후 검증 의무 |
| Alt+R (실행) | NVIDIA 충돌 (사용자 환경) |
영향 파일
• Assets/Scripts/Game/CameraViewController.cs L213 — F Alt 가드
• Assets/Scripts/Game/Factory00Bootstrap.cs L4316~4319 — H Alt 가드
다음 자율 큐
QA-119 v0.1.407 재검증 + Alt+F/H 재검증 + Alt+R 대체 키 (사용자 명시 후) + STD-0003 정합.

v0.1.407 — v0.1.407 — QA-014 SetPresetView 가드 제거 + QA-119 잔존 부품 트리 fix

v0.1.407 v0.1.407 — QA-014 SetPresetView 가드 제거 + QA-119 잔존 부품 트리 fix zip release notes GitHub
핵심 변경
1. QA-014 SetPresetView FirstPerson 가드 제거
• 사용자 보고 (2026-05-26 01:00): "뷰 메뉴 v0.1.398 보강 fix : 7개 뷰 메뉴 모두 오른쪽에 토스트 메시지만 출력되고 뷰가 바뀌지 않음"
• root cause: CameraViewController.SetPresetView L612 if (_mode == CameraViewMode.FirstPerson) return; — 1인칭 상태 갇히면 모든 뷰 메뉴 무동작
• fix: 가드 제거. 1인칭 상태여도 Default 모드로 강제 전환 + 새 yaw/pitch 적용
2. QA-119 잔존 부품 트리 깨짐 fix
• 사용자 보고 (2026-05-26 01:05): "프로젝트 불러오기 v0.1.401 : 불러오기는 되는데 부품 트리가 전부 깨진다"
• root cause: STEP 자동 재임포트가 새 GUID 사용 → payload Part id와 매칭 안 됨 → ApplyTwnPayload byId 매칭 실패 → Transform/Sensors/Actuators 메타 미반영
• fix: STEP 임포트 직후 신규 Part id/parentId를 payload 순서대로 덮어쓰기 (같은 STEP 파일 = 결정적 임포트 순서 가정)
사용자 PASS 누적 (본 cap)
| 시각 | 영역 | 빌드 |
|---|---|---|
| 22:55 | QA-118 옛 F-key | v0.1.390 |
| 23:00 | F5~F8 + F4 토글 | v0.1.390 |
| 23:10 | PhotoSensor 라인 | v0.1.394 |
| 00:55 | 와이어프레임 토글 F3 | v0.1.399 |
| 01:00 | 공압 Gizmo 거리 | v0.1.400 |
영향 파일
• Assets/Scripts/Game/CameraViewController.cs L608~615 — SetPresetView FirstPerson 가드 제거
• Assets/Scripts/Game/Factory00Bootstrap.cs L2769~2800 — STEP 재임포트 후 Part id/parentId 덮어쓰기
다음 자율 큐
QA-119 사용자 PC 재검증 → STD-0003 RuntimeGizmo 정합 → Group B SNB.

v0.1.406 — v0.1.406 — 접기 버튼 -40px (사용자 4번째 보고 fix)

v0.1.406 v0.1.406 — 접기 버튼 -40px (사용자 4번째 보고 fix) zip release notes GitHub
핵심 변경
• 좌측 패널 접기 버튼 (c-sidebar-edge-btn--collapse) right -32px → -40px
• 사용자 보고 (2026-05-26 v0.1.405 시점): "좌우 레이아웃 조정 세로줄과 겹친다. 해당 세로줄 두께만큼만 오른쪽으로 이동"
• splitter 외 추가 세로줄 (panel border + body border 등) 회피
사용자 보고 history (접기 버튼 위치)
| 보고 | 빌드 | right |
|---|---|---|
| 처음 보고 "세로줄과 겹친다" | v0.1.394 | -27 → -50 |
| 두 번째 보고 "너무 멀다" | v0.1.397 | -50 → -32 |
| 세 번째 보고 "겹친다" | v0.1.406 (본 빌드) | -32 → -40 |
와이어프레임 토글 PASS
사용자 명시 (2026-05-26 00:55): "와이어프레임 토글 (F3) : 매우 잘 동작함" → v0.1.399 신규 기능 정상 동작 확정.
영향 파일
• Assets/UI/Components/ribbon.uss L207~217 — .c-sidebar-edge-btn--collapse right -40px
다음 자율 큐
QA-110 사용자 PC 검증 → Group B SNB 트리 옵션 C → STD-0003 RuntimeGizmo 정합.

v0.1.405 — v0.1.405 — Group A QA-110 ghost fix (Pneumatic visualizer 부모 변경)

v0.1.405 v0.1.405 — Group A QA-110 ghost fix (Pneumatic visualizer 부모 변경) zip release notes GitHub
핵심 변경 (Group A QA-110 root cause fix)
• PneumaticStrokeBarVisualizer GameObject 부모를 ownerPart에서 ActuatorDriver로 변경
• ActuatorDriver L52 SetParent(ownerPart.cachedTransform, false) → SetParent(transform, false)
QA-110 root cause + fix
| 영역 | 기존 | v0.1.405 fix |
|---|---|---|
| Pneumatic 시각화 부모 | ownerPart.cachedTransform 자식 | ActuatorDriver 자식 |
| DuplicateCommand origGo Instantiate | 자식 시각화도 자동 복사 = ghost | 시각화 별도 부모 = 미복사 |
| RegisterDuplicatedComponents | 신규 부품에 새 visualizer 등록 | 동일 (정상 path 보존) |
| Update 위치 추적 | ownerPart.cachedTransform 자식이라 자동 따라감 | 매 frame _ownerPart.cachedTransform.position 사용 (이미 구현됨) |
| LineRenderer.useWorldSpace | true | true (영향 0) |
| PartBoundsExclude marker | visGo 직접 부착 | 동일 (부모 무관 BBox 제외 보장) |
PhotoSensor 패턴 미러
기존 PhotoSensorVisualizer (SensorPollingDriver.cs L39)는 SensorPollingDriver 자식이라 같은 ghost 문제 없음. 본 fix로 PneumaticStrokeBar도 같은 패턴 미러.
Group A QA-110/111/114 처리 누계
| QA | 본 cap |
|---|---|
| QA-110 (Duplicate ghost) | v0.1.405 fix |
| QA-111 (deselect 잔존) | v0.1.396 fix |
| QA-114 (Delete 잔존) | v0.1.396 fix |
= Group A 3건 완료.
영향 파일
• Assets/Scripts/Actuators/ActuatorDriver.cs L52 — SetParent transform
다음 자율 큐
Group B SNB 트리 옵션 C → STD-0003 RuntimeGizmo 정합 → QA-086 이동/리사이즈.

v0.1.404 — v0.1.404 — Group F QA-086 서브윈도우 z-order fix + 이모지 잔존 정리

v0.1.404 v0.1.404 — Group F QA-086 서브윈도우 z-order fix + 이모지 잔존 정리 zip release notes GitHub
핵심 변경
Group F QA-086 z-order fix
• OpenPartInSubWindow 안 _subWindowOverlay.BringToFront() 호출 추가 (L8170)
• root cause: root.Add(_subWindowOverlay)는 마지막 자식이지만 LNB hud-root.BringToFront (L3456) + ribbon-commands reparent (L1605) 후속 호출 시 z-order 뒤로 밀림
• fix: 명시 BringToFront로 최상위 보장
이모지 잔존 일괄 제거
• v0.1.402 빌드 후 index.html / latest-builds.html 2건 잔존 발견
• sed 일괄 제거 + build-title 갱신 후 검증 0건
Group F 잔존
| QA | 영역 | 본 cap 처리 |
|---|---|---|
| QA-086 z-order | 서브윈도우 SNB 뒤 숨김 | v0.1.404 fix |
| QA-086 이동·리사이즈 | 타이틀 드래그 + 테두리 리사이즈 | 별도 사이클 (UI 구조 변경) |
| QA-097 씬 click 미닫힘 | GlobalMouseDown 전파 | 별도 사이클 (큰 fix) |
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs L8170 — BringToFront
wiki/index.html / wiki/latest-builds.html — 제거
다음 자율 큐
QA-097 GlobalMouseDown 전파 → Group B SNB 트리 → QA-086 이동·리사이즈.

v0.1.403 — v0.1.403 — Group D QA-102 #7 부품이동 잔존 fix (drag 후 outline 갱신)

v0.1.403 v0.1.403 — Group D QA-102 #7 부품이동 잔존 fix (drag 후 outline 갱신) zip release notes GitHub
핵심 변경 (Group D #7 fix)
OnDragEnded 안 HighlightSelectedParts 호출 추가 (Factory00Bootstrap L5028)
• root cause: RuntimeGizmo drag 종료 시 TransformCommand UndoStack push만, outline 위치 갱신 누락 → 원래 위치 outline 잔존
QA-102 9건 처리 누계 (v0.1.403 시점)
| # | 영역 | 본 cap 처리 |
|---|---|---|
| 1 | Alt+mnemonic | v0.1.402 fix |
| 2 | Recent 하위메뉴 변경 | PM 답변 의무 (명세 변경) |
| 3 | Ctrl+Z UndoStack | fix 완료 (PM r109 종결) |
| 4 | Ctrl+X 씬 click | fix 완료 (L4253 v0.1.289 P3) |
| 5 | Delete 포커스 소실 | fix 완료 (PM r109 종결) |
| 6 | 카메라 프리셋 | fix 완료 (v0.1.398 보강) |
| 7 | 부품이동 잔존 | v0.1.403 fix |
| 8 | Inspector 우측 미분리 | 명세 변경 영역 |
| 9 | 실행 메뉴 | fix 완료 (Ribbon tab-run) |
= 9건 중 7건 fix (#1/#3/#4/#5/#6/#7/#9). 잔존 2건 (#2/#8) PM 답변 의무.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs L5028 — OnDragEnded HighlightSelectedParts 호출
다음 자율 큐
QA-102 #2/#8 PM 답변 후 진입 → Group B SNB 트리 → Group F 서브윈도우.

v0.1.402 — v0.1.402 — Group D QA-102 #1 Alt+mnemonic 메뉴 단축키 (Windows 표준)

v0.1.402 v0.1.402 — Group D QA-102 #1 Alt+mnemonic 메뉴 단축키 (Windows 표준) zip release notes GitHub
핵심 변경 (Group D #1 fix)
Alt+F=파일 / Alt+E=편집 / Alt+V=뷰 / Alt+C=부품/컴포넌트 / Alt+R=실행 / Alt+T=도구 / Alt+H=도움말 7키 매핑
• Update L4373~4395 — Alt 키 처리 블록 안 mnemonic 단축키 추가
• 동작 path: Alt+key → tab-{name} button.Q → NavigationSubmitEvent SendEvent (UI Toolkit 표준 click 패턴)
QA-102 9건 cross-check (v0.1.401 시점)
| # | 영역 | 상태 |
|---|---|---|
| 1 | Alt+mnemonic | v0.1.402 fix (본 빌드) |
| 2 | Recent 하위메뉴 변경 | PM 답변 의무 (명세 변경) |
| 3 | Ctrl+Z UndoStack | fix 완료 (이동/회전 PushExecuted L4998) — PM r109 검증 종결 |
| 4 | Ctrl+X 씬 click | 등록 있음 (L4253) — 진단 영역 |
| 5 | Delete 포커스 소실 | fix 완료 (L4257 IsAnyTextFieldFocused 가드) — PM r109 검증 종결 |
| 6 | 전체보기+카메라 프리셋 | fix 완료 (v0.1.398 QA-014 보강) — PM r109 검증 종결 |
| 7 | 부품이동 잔존 | 진단 영역 |
| 8 | Inspector 우측 미분리 | 자체 측 우측 패널 정상 (명세 변경) |
| 9 | 실행 메뉴 | fix 완료 (Ribbon.uxml L14 tab-run) — PM r109 검증 종결 |
= 9건 중 5건 fix 완료 (#1/#3/#5/#6/#9). 잔존 4건 (#2/#4/#7/#8) 진단 영역.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs L4373~4395 — Alt+mnemonic 7키 매핑
다음 자율 큐
QA-102 #4 (Ctrl+X 씬 click) + #7 (부품이동 잔존) 진단 → Group B SNB 트리.

v0.1.401 — v0.1.401 — Group C QA-119 옵션 B fix (STEP 자동 재임포트)

v0.1.401 v0.1.401 — Group C QA-119 옵션 B fix (STEP 자동 재임포트) zip release notes GitHub
핵심 변경 (Group C — QA-119 Save/Load 빈 씬 fix)
1. TwnProjectInfo 확장 (project file format v2)
string stepSourcePath 필드 신규 — STEP 원본 경로 직렬화
2. Bootstrap 변수 + capture
_lastStepPath 변수 추가 (런타임 capture)
• STEP 임포트 성공 시 자동 capture (L1773)
• SaveProject 시 stepSourcePath = _lastStepPath 저장 (L3023)
3. Open 시 자동 STEP 재임포트
OpenTwnPath async 변경
• 조건: stepSourcePath != "" + File.Exists + scenePartsCount < payloadPartsCount
• 동작: ConvertStepToGlbAsync + ImportGlbAsync 자동 호출 → ApplyTwnPayload 속성 덮어쓰기
QA-119 root cause + fix path
| 단계 | v0.1.400 이전 | v0.1.401 fix |
|---|---|---|
| .twn 안 STEP 경로 | 부재 | TwnProjectInfo.stepSourcePath |
| Save 시 capture | 없음 | _lastStepPath → stepSourcePath |
| Open 시 GameObject 생성 | ApplyTwnPayloadCore byId 매칭만 (else branch X) | 자동 STEP 재임포트 → Parts.AddRange → ApplyTwnPayload |
| 빈 씬 Open | 0개 로드 | 자동 재임포트 → 전체 복원 |
| 삭제 후 Open | 미복원 | 자동 재임포트 → 신규 생성 |
영향 파일
Assets/Scripts/Project/TwnProjectFile.cs L77~80 — stepSourcePath 필드
Assets/Scripts/Game/Factory00Bootstrap.cs L2619~2623 — _lastStepPath 변수
Assets/Scripts/Game/Factory00Bootstrap.cs L1773 — STEP 임포트 capture
Assets/Scripts/Game/Factory00Bootstrap.cs L3023 — SaveProject 저장
Assets/Scripts/Game/Factory00Bootstrap.cs L2752~2800 — OpenTwnPath async + 자동 재임포트
호환성
기존 .twn 파일 (v0.1.400 이전) = stepSourcePath = "" (빈 문자열). 자동 재임포트 path skip = 기존 동작 보존.
다음 자율 큐
QA-119 사용자 PC 검증 → Group D QA-102 메뉴 IA 9건 → Group B SNB 트리.

v0.1.400 — v0.1.400 — Task #153 Gizmo 거리 불일치 fix (hierarchy 자식 dedup)

v0.1.400 v0.1.400 — Task #153 Gizmo 거리 불일치 fix (hierarchy 자식 dedup) zip release notes GitHub
핵심 변경 (Task #153 — 사용자 보고)
UpdateGizmoTargets hierarchy 자식 dedup (Bootstrap L4968~5005): SetTargets 진입 시 다른 항목의 IsChildOf 자식이면 skip. 부모만 SetTargets.
• root cause: CollectDescendants가 부모 + 자식 Part 모두 _selectedParts 추가 → 자식 cachedTransform이 부모 hierarchy 자식 → drag 시 부모 .position += delta (Unity 자동 자식 따라감) + 자식 .position += delta = 2배 누적.
Task #153 사용자 보고 (2026-05-25 23:15)
"공압 실린더 부품 부착 후 기즈모 위치 이상함. 그리고 기즈모 드래그 시에도 기즈모가 움직이는 거리와 오브젝트가 움직이는 거리가 다름(기즈모 보다 오브젝트가 더 많이 움직임)"
진단 path
| 영역 | 발견 |
|---|---|
| RuntimeGizmo L851~855 | t.position = _initialPositions[idx] + delta — world position, 정상 |
| UpdateGizmoTargets | _selectedParts 안 모든 cachedTransform SetTargets — hierarchy dedup 누락 |
| CollectDescendants L4713 | root + parentId 기반 모든 자손 Part 추가 |
| PneumaticStrokeBarVisualizer | ownerPart.cachedTransform 자식 — Part 객체 아님 (별도 영역) |
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs L4968~5005 — UpdateGizmoTargets hierarchy dedup 추가
v0.1.400 milestone
자체 측 안정화 시작 v0.1.000 (2026-05-10) 이후 400번째 빌드. 본 cap 누적 11번째 stable seal 후보.
다음 자율 큐
Group C QA-119 Save/Load 옵션 B → Group D QA-102 메뉴 IA 9건 → Group B SNB 트리 데이터 모델.

v0.1.399 — v0.1.399 — PhotoSensor 라인 red + Wireframe 토글 (F3 단축키, CAD 표준)

v0.1.399 v0.1.399 — PhotoSensor 라인 red + Wireframe 토글 (F3 단축키, CAD 표준) zip release notes GitHub
핵심 변경 (사용자 직접 보고 통합)
PhotoSensor 라인 컬러
PhotoSensorVisualizer.cs L147Color hi = new Color(1f, 1f, 1f, 0.95f)Color(1f, 0.15f, 0.15f, 0.95f) (흰색 → 빨강)
• 사용자 명시 (2026-05-25 23:10): "센서 타겟 라인 수정 확인. 컬러 red로 하자"
Wireframe 토글 (신규 기능, 사용자 명시)
단축키: F3 (CAD 표준 — 3ds Max 표준 단축키)
위치: 뷰(V) 메뉴 → 와이어프레임 (Wireframe) F3 (view-iso 하단 divider 다음)
구현:
WireframeService.cs 신설 (SSOT) — RenderPipelineManager.beginCameraRendering hook + GL.wireframe + PlayerPrefs 저장
CameraViewController.cs L192~200 — F3 KeyDown → ToggleWireframe + OnWireframeToggled callback
Ribbon.uxml L69 — view-wireframe button 추가
Factory00Bootstrap.cs L2408~2424 — view-wireframe binding + FlashToast
사용자 직접 보고 처리 (2026-05-25 23:10~23:20)
| 시각 | 보고 | 본 빌드 처리 |
|---|---|---|
| 23:10 | PhotoSensor 라인 PASS + red | red color 적용 |
| 23:20 | Wireframe 토글 기능 + CAD 단축키 | F3 + UXML 메뉴 |
CAD 와이어프레임 단축키 표준 비교
| 도구 | 단축키 | 자체 채택 |
|---|---|---|
| 3ds Max | F3 | (O) |
| Maya | 4 (와이어), 5 (셰이드) | — |
| Blender | Shift+Z | — |
| SketchUp | Alt+1 | — |
| AutoCAD/SolidWorks | 메뉴만 | — |
F3 = 직관 + 자체 미사용 (v0.1.390 fix로 옛 F3 매핑 제거).
영향 파일
Assets/Scripts/Game/WireframeService.cs 신설 (~75라인, SSOT)
Assets/Scripts/Game/CameraViewController.cs L192~200 — F3 KeyDown + L178 OnWireframeToggled callback
Assets/UI/Components/Ribbon.uxml L69 — view-wireframe button
Assets/Scripts/Game/Factory00Bootstrap.cs L2408~2424 — button binding + 토스트
Assets/Scripts/Sensors/PhotoSensorVisualizer.cs L147 — red color
다음 자율 큐
Task #153 공압 Gizmo 거리 불일치 root cause → Group C QA-119 → Group D QA-102.

v0.1.398 — v0.1.398 — QA-014 보강 fix (ApplyPresetCameraPosition SSOT) + 접기 버튼 -32px

v0.1.398 v0.1.398 — QA-014 보강 fix (ApplyPresetCameraPosition SSOT) + 접기 버튼 -32px zip release notes GitHub
핵심 변경 (사용자 직접 보고 통합)
QA-014 보강 fix: ApplyMode CameraViewMode.Default 분기 → ApplyPresetCameraPosition() 호출로 변경. v0.1.391 fix의 fallback 순서 잘못 (target.position 우선) → 모든 orbit 모드 (Default/Top/Side/Front/Right/Isometric) 동일 SSOT 사용 (_boundsCenter 우선 → target.position fallback)
접기 버튼 -32px: 사용자 보고 "v0.1.394 -50px 너무 멈" → 적정값 (splitter 8 + gap 6 + width 18 = 32)
QA-014 보강 root cause (사용자 보고 "View:Front 메시지 + 카메라 미전환")
| 영역 | 위치 | 진단 |
|---|---|---|
| SetPresetView → ApplyMode(Default) | L600 | 호출 정상 (FlashToast 발화 OK) |
| ApplyMode Default v0.1.391 fix | L272~287 | fallback 순서 target.position 우선 → STEP 모델 LoadedRoot.position = 원점, BBox center 다른 위치 |
| ApplyPresetCameraPosition (SSOT) | L260~269 | _boundsCenter 우선 → target.position fallback (Top/Side/Iso 이미 사용 중) |
영향 파일
Assets/Scripts/Game/CameraViewController.cs L272~280 — ApplyMode Default 분기 → ApplyPresetCameraPosition 호출
Assets/UI/Components/ribbon.uss L207~214 — .c-sidebar-edge-btn--collapse right -32px
사용자 직접 보고 누적 (2026-05-25)
| 시각 | 보고 | 처리 |
|---|---|---|
| 22:55 | QA-118 옛 F2/F3/F4 PASS | 검증 완료 |
| 23:00 | F5~F8 + F4 토글 정상 | 검증 완료 |
| 23:05 | 접기 버튼 너무 멈 | 본 빌드 -32px |
| 23:10 | 뷰 메뉴 카메라 프리셋 미전환 | 본 빌드 보강 fix |
| 23:15 | 공압 Gizmo 위치/거리 불일치 | Task #153 별도 사이클 |
다음 자율 큐
Task #153 공압 Gizmo 거리 불일치 진단 → Group C QA-119 → Group D QA-102.

v0.1.397 — v0.1.397 — Group E QA-081 1인칭 모드 fix (Space/C 키 + BBox LookAt fallback)

v0.1.397 v0.1.397 — Group E QA-081 1인칭 모드 fix (Space/C 키 + BBox LookAt fallback) zip release notes GitHub
핵심 변경 (Group E — QA-081 부분 fix)
WASD/Space/C 추가: UpdateFirstPerson L530~535 — Space (up) + C (down) 추가. Q/E 호환 유지
BBox LookAt fallback: ApplyMode FirstPerson L334~346 — target null 시 _boundsCenter fallback (QA-014 fix 동일 패턴). 빈 씬 또는 target 미할당 환경에서도 BBox 중심 LookAt 동작
QA-081 처리 분류
| 영역 | 본 cycle | 다음 |
|---|---|---|
| WASD/Space/C 미동작 | fix (Space/C 추가) | PASS 검증 |
| BBox LookAt 미동작 | fix (target null fallback) | PASS 검증 |
| 카메라 이동 시 모델 소멸 | 별도 사이클 진단 (near/far clipping plane 영역) | 별도 |
영향 파일
Assets/Scripts/Game/CameraViewController.cs L530~535 — UpdateFirstPerson Space/C 추가
Assets/Scripts/Game/CameraViewController.cs L330~348 — ApplyMode FirstPerson target null fallback
다음 자율 큐
QA-081 모델 소멸 별도 진단 → Group C QA-119 Save/Load 옵션 B → Group D QA-102 메뉴 IA 9건.

v0.1.396 — v0.1.396 — Group A QA-111/114 IndicatorManager 단순 fix (visualizer lifecycle 2 path)

v0.1.396 v0.1.396 — Group A QA-111/114 IndicatorManager 단순 fix (visualizer lifecycle 2 path) zip release notes GitHub
핵심 변경 (Group A — QA-111 + QA-114 통합)
QA-114 fix: PhotoSensorVisualizer.Update L72~83 — ownerPart cachedTransform inactive 시 visualizer hide. DeleteCommand SetActive(false) 호출 시 visualizer GameObject는 SensorPollingDriver 자식이라 parent inactive 상속 안 됨 → 명시 검증.
QA-111 fix: OnSelectionChanged L4715~4717 — SensorPollingDriver / ActuatorDriver SetSelectedPart(root) 호출 추가 (root null 포함). ESC/빈 click 시 visualizer 가시성 즉시 해제.
Group A root cause (3 path 통합 분석)
| QA | root cause | 본 cycle 처리 |
|---|---|---|
| QA-111 (deselect 잔존) | SetSelectedPart(null) 호출 path 부재 | PASS — OnSelectionChanged에 양 driver 호출 추가 |
| QA-114 (Delete 잔존) | visualizer GameObject가 SensorPollingDriver 자식 = parent inactive 상속 안 됨 | PASS — Update 안 ownerPart activeSelf 검증 |
| QA-110 (Duplicate ghost) | RegisterDuplicatedComponents 정상 path 확인 (다른 root cause 가능) | 별도 사이클 진단 |
영향 파일
Assets/Scripts/Sensors/PhotoSensorVisualizer.cs L72~83 — Update ownerPart activeSelf 검증
Assets/Scripts/Game/Factory00Bootstrap.cs L4715~4717 — OnSelectionChanged SetSelectedPart 호출
다음 자율 큐
QA-110 ghost root cause 정밀 진단 → Group E QA-081 1인칭 → Group C QA-119 Save/Load.

v0.1.395 — v0.1.395 — Group G QA-106 Inspector 텍스트필드 fix (FocusIn/MouseDown 핸들러 추가)

v0.1.395 v0.1.395 — Group G QA-106 Inspector 텍스트필드 fix (FocusIn/MouseDown 핸들러 추가) zip release notes GitHub
핵심 변경 (Group G — QA-106 재탈락 fix)
NoteInspectorInteraction 호출처 확장 (Factory00Bootstrap.cs L5189~5196):
◦ 기존: KeyDown / ChangeEvent (string/float/int/bool) / PointerDown
신규 추가: FocusInEvent + MouseDownEvent
• TextField focus 받자마자 grace timer (1.5s) 시작 → 클릭 직후 RenderInspector 호출 방지
QA-106 root cause (코드 검증)
| 영역 | 위치 | 발견 |
|---|---|---|
| 주기 RenderInspector | L4384~4387 | IsInspectorEditFocused + IsInspectorRecentlyInteracted 가드 |
| NoteInspectorInteraction trigger | L5189~5194 | KeyDown + ChangeEvent + PointerDown만 — FocusIn/MouseDown 부재 |
TextField 클릭만으로는 PointerDown만 발화 → grace timer 시작은 OK이지만 UI Toolkit 환경에 따라 MouseDownEvent 별도 발화 필요 (TextField 내부 elements). FocusIn 추가로 focus 획득 시점 즉시 grace timer 시작 보장.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs L5186~5198 — FocusInEvent + MouseDownEvent 추가 (2건)
다음 자율 큐
Group A QA-110/111/114 IndicatorManager 통합 → Group E QA-081 1인칭 → Group C QA-119 Save/Load.

v0.1.394 — v0.1.394 — 사용자 직접 보고 2건 통합 (접기 버튼 + PhotoSensor 라인)

v0.1.394 v0.1.394 — 사용자 직접 보고 2건 통합 (접기 버튼 + PhotoSensor 라인) zip release notes GitHub
핵심 변경 (Group H — 사용자 직접 보고 즉시 fix)
접기 버튼 세로줄 겹침 fix (Task #148): c-sidebar-edge-btn--collapse right -27px-50px. splitter 6px + border 2px + body border + 24px gap 충분 회피
PhotoSensor _targetLR zoom-invariant + 얇은 선 (Task #149): 카메라 거리 비례 width 갱신. orthographic = orthographicSize × 2, perspective = Vector3.Distance × 0.0015. 최소 2mm 보장 + 화면상 ~1.5px 두께 유지
영향 파일
Assets/UI/Components/ribbon.uss L207~213 — .c-sidebar-edge-btn--collapse right -50px
Assets/Scripts/Sensors/PhotoSensorVisualizer.cs L133~165 — _targetLR width 카메라 거리 비례 갱신
사용자 보고 path
| 보고 | 시각 | 영역 |
|---|---|---|
| 접기 버튼 세로줄 겹침 (스크린샷) | 2026-05-25 22:10 KST | UI layout |
| PhotoSensor 타겟 라인 zoom 사이즈 변동 | 2026-05-25 22:15 KST | 3D visualizer |
QA 그룹화 전략 (사용자 명시 2026-05-25)
본 cap 진척 = 작은 사이클 누적 (6분 cap). 사용자 명시 "연관된 버그 모아서 한번에 처리" 후 그룹 단위 일괄 처리 전환.
| Group | QA | 사이클 |
|---|---|---|
| H (즉시) | 접기 버튼 + PhotoSensor 라인 | v0.1.394 (본 빌드) |
| G | QA-106 Inspector | 1-2 cycle |
| A | QA-110/111/114 IndicatorManager | 1 cycle (PM D-2안) |
| E | QA-081 1인칭 모드 | 1 cycle |
| C | QA-119 Save/Load 옵션 B | 2 cycle |
| D | QA-102 메뉴 IA 9건 | 2-3 cycle |
| B | QA-108/112/117 SNB | 2 cycle |
| F | QA-086/097 서브윈도우 | 1-2 cycle |
다음 자율 큐
Group G QA-106 Inspector → Group A 인디케이터 lifecycle → Group E 1인칭 → Group C Save/Load.

v0.1.393 — v0.1.393 — QA-014/QA-044 진단 로그 8건 revert (binary search 잔존 정리)

v0.1.393 v0.1.393 — QA-014/QA-044 진단 로그 8건 revert (binary search 잔존 정리) zip release notes GitHub
핵심 변경 (룰 binary-search-code-tracking.md 즉시 입증)
[QA-014 진단] Debug.Log 7건 revert — SetupRibbonShell entry / view-fit/ortho/save/load click / BindRibbonViewCommand View click
[QA-044 진단] Debug.Log 2건 revert — ApplyTwnPayload ENTRY / EXIT OK
LogWarning/LogError 7건 보존 — view-* Button NOT FOUND / ApplyTwnPayload FAIL / Parts id 중복 skip (WARN/ERROR 발생 시만 출력)
룰 영구화 ROI 즉시 입증
본 cap 사이클 20 안 .claude/rules/binary-search-code-tracking.md 영구화 직후 자체 측 잔존 진단 로그 15건 발견 (v0.1.391 fix 완료 후 정상 동작 시 매번 발화). 룰 가치 즉시 입증.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs L1593 / 2416 / 2427 / 2441 / 2450 / 3143 / 3147 / 3383 — Debug.Log 8건 → 주석 치환
의도된 잔존 (보존)
| 위치 | 종류 | 보존 사유 |
|---|---|---|
| L2412 / 2423 / 2437 / 2446 / 3380 | Debug.LogWarning view-* Button NOT FOUND | UI 결함 발생 시만 출력, 사용자 진단 가치 |
| L3151 | Debug.LogError ApplyTwnPayload FAIL | Open 실패 시만 출력, 사용자 디버깅 핵심 |
| L3176 | Debug.LogWarning Parts id 중복 skip | 중복 발견 시만 출력, 정상 동작 + 진단 가치 |
다음 자율 큐
QA-119 옵션 B (LoadProject STEP 자동 재임포트) → QA-108 옵션 C (자식 row 모방) → QA-106 Inspector 텍스트필드.

v0.1.392 — v0.1.392 — QA-105 후속 Pneumatic visualizer 자동 부착 활성화 (binary search 잔존 revert)

v0.1.392 v0.1.392 — QA-105 후속 Pneumatic visualizer 자동 부착 활성화 (binary search 잔존 revert) zip release notes GitHub
핵심 변경 (QA-105 후속 fix)
ActuatorDriver.cs L44~55 #if false ... #endif 제거 — PneumaticStrokeBar visualizer 자동 부착 활성화
• v0.1.382 binary search 시 임시 비활성화된 코드. v0.1.387 51st seal REAL FIX 시 다른 binary search 코드는 모두 revert 됐으나 본 영역만 revert 누락 발견.
QA-105 후속 root cause (코드 검증)
| 영역 | 위치 | 발견 |
|---|---|---|
| ActuatorDriver.RegisterActuator | L44~55 | #if false Pneumatic 자동 visualizer 부착 영구 비활성화 (v0.1.382 잔존) |
| PneumaticStrokeBarVisualizer.cs | L82 | PartBoundsExclude marker 이미 적용 (정상) |
PM r108 보고 "5종 정상 / Pneumatic 단독 잔존" = visualizer 부착이 안 됐기 때문에 marker 적용 path도 동작 안 함. fix = #if false 제거 후 정상 활성화.
51st seal 회기 학습
v0.1.382~386 binary search 시 임시 비활성화 코드들이 v0.1.387 REAL FIX에서 모두 revert 의무. 본 영역은 ActuatorDriver.cs 단일 위치 revert 누락 = 향후 binary search 시 모든 변경 위치 명시 보고 의무 (룰 영구화 검토).
영향 파일
Assets/Scripts/Actuators/ActuatorDriver.cs L44~57 — #if false 제거 + 활성화 코멘트
다음 자율 큐
QA-119 LoadProject 옵션 B (STEP 자동 재임포트) → QA-108 옵션 C (자식 row 모방) → QA-106 Inspector 텍스트필드.

v0.1.391 — v0.1.391 — QA-014 뷰 메뉴 카메라 프리셋 7종 wiring fix (target null fallback)

v0.1.391 v0.1.391 — QA-014 뷰 메뉴 카메라 프리셋 7종 wiring fix (target null fallback) zip release notes GitHub
핵심 변경 (QA-014 fix · ApplyMode Default fallback)
CameraViewController.ApplyMode CameraViewMode.Default 분기 fallback 추가 — target null 시 _boundsCenter fallback, 빈 씬 시 월드 원점
• v0.1.391 fix scope: ~7라인 변경 (단일 case 분기)
QA-014 root cause (코드 검증 후 확정)
| 영역 | 위치 | 발견 |
|---|---|---|
| SetPresetView | CameraViewController L595 | if (_mode == FirstPerson) return; _orbitYawPitch 갱신; ApplyMode(Default); |
| ApplyMode Default | L272~283 | if (target != null) {...} 가드 = target null 시 cam.transform 갱신 안 됨 |
뷰(V) 메뉴 Ribbon view-front/back/left/right/top/bottom/iso 7종 모두 SetPresetView 호출 → ApplyMode(Default) → target null 시 무동작.
fix 패턴
`csharp
case CameraViewMode.Default:
cam.orthographic = false;
cam.fieldOfView = 60f;
{
Vector3 centerDef = target != null ? target.position
: (_boundsCenter != Vector3.zero ? _boundsCenter : Vector3.zero);
var rot = Quaternion.Euler(_orbitYawPitch.x, _orbitYawPitch.y, 0f);
cam.transform.position = centerDef + _orbitPanOffset + rot * (Vector3.back * orbitDistance);
cam.transform.rotation = rot;
}
break;
`
L259~263 주석 패턴 ("F1 Default 패턴 미러 — _boundsCenter 우선, target.position fallback. 빈 씬은 월드 원점") 명시 의도와 정합.
영향 파일
Assets/Scripts/Game/CameraViewController.cs L272-285 — ApplyMode Default 분기 fallback 추가
영향 영역 (PASS 예상)
| Button | yaw | pitch | 동작 |
|---|---|---|---|
| view-front (정면) | 0 | 0 | SetPresetView(0,0) → 카메라 +Z 방향 |
| view-back (후면) | 180 | 0 | SetPresetView(180,0) → 카메라 -Z 방향 |
| view-left (왼쪽) | -90 | 0 | -X 방향 |
| view-right (오른쪽) | 90 | 0 | +X 방향 |
| view-top (위) | 0 | 89 | 위에서 본 평면 |
| view-bottom (아래) | 0 | -89 | 아래에서 본 평면 |
| view-iso (등각) | 45 | 35.264 | 등각 투영 |
다음 자율 큐
QA-108 SNB 자식 노드 (Task #138) → QA-119 LoadProject (Task #143).

v0.1.390 — v0.1.390 — QA-118 옛 F2/F3/F4 카메라 단축키 잔재 제거 + 신규 매핑

v0.1.390 v0.1.390 — QA-118 옛 F2/F3/F4 카메라 단축키 잔재 제거 + 신규 매핑 zip release notes GitHub
핵심 변경 (QA-118 fix)
CameraViewController.cs 옛 F2/F3/F4/F5 매핑 제거 — QA-081 r023 단축키 변경 사후 정리 누락
CameraViewMode enum +2: Front (정면, F5) + Right (오른쪽, F6)
신규 단축키 매핑 SSOT:
◦ F4 = 시점모드 토글 (Default ↔ FirstPerson)
◦ F5 = Front / F6 = Right / F7 = Top / F8 = Isometric
Bootstrap.HandlePartFilterShortcuts F4~F8 단축키 5건 제거 (QA-030 PM 요청 정합)
QA-118 root cause (코드 검증 후 확정)
| 영역 | 위치 | 발견 |
|---|---|---|
| CameraViewController | L186~191 | 옛 F2→Top / F3→Side / F4→Iso / F5→FirstPerson 잔존 |
| Bootstrap PartFilterMode | L4549~4553 | F4~F8 = All/HiddenOnly/VisibleOnly/WithActuator/WithoutActuator |
F4/F5 동시 발화 = 카메라 모드 + PartFilterMode 충돌. 사용자 보고 "F2~F4 우측하단 오프셋" = 옛 매핑이 카메라 이동 트리거 + 추가 ApplyMode BBox 누적 가능성 (별도 사이클 검증).
QA-030 동시 해소
PM 측 v0.1.389 spot-check 결과 QA-030 부분 통과 (단축키 삭제 요청) — 본 fix와 동시 해소. PartFilterMode 단축키 제거 = 부품 리스트 드롭다운 UI 단독 (S0019 미할당 + S0014 r005 정합).
영향 파일
Assets/Scripts/Game/CameraViewController.cs — enum +2, ApplyMode +14라인, Update 매핑 변경
Assets/Scripts/Game/Factory00Bootstrap.cs — HandlePartFilterShortcuts F4~F8 5건 제거
하네스 보강 (동시 사이클)
handoff.md SSOT 신규 — html→md 자동 변환 도구 (Tools/sync-handoff-md.sh)
dev/dev_handoff.md push 자동화 — Tools/push-dev-handoff.sh (협업자 repo 유일 예외)
publish-build-auto.sh §7.55/§7.56 hook 통합 — 매 빌드 자동 md sync + push
sync-handoff-fragment.sh §5/§6 hook 통합 — 폴리시 사이클 자동 md sync + push
룰 collab-repo-pull-only.md 예외 명시 — ALLOW_DEV_HANDOFF_PUSH=1 + staged 검증
validate-push.sh 예외 검증 — staged files = dev/dev_handoff.md 단일 의무
다음 자율 큐
QA-014 메뉴 wiring fix (Task #137) → QA-108 SNB 자식 노드 (Task #138) → QA-119 LoadProject (Task #143) → QA-120 standards 정합 (Task #141)

v0.1.389 — v0.1.389 — dead code cleanup + TODO 잔재 제거

v0.1.389 v0.1.389 — dead code cleanup + TODO 잔재 제거 zip release notes GitHub
핵심 변경
• RemoveRuntimeComponents_DEAD 메서드 제거 (~17라인) — deprecated-spec-marking.md 룰 의무. v0.1.243 QA-021 정책 변경 후 호출처 0건. 향후 재활용 시 git log v0.1.243 복원 가능.
• /* TODO: next match */ 잔재 제거 → no-op 명시 + 도입 spec 주석 추가.
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — 17라인 삭제 + 3라인 갱신 (총 -14라인, 9608→9594)
협업자 spec 영향
• spec 영향 0 (내부 cleanup)

v0.1.388 — v0.1.388 — QA-109 Duplicate Material blink color 영구화 fix

v0.1.388 v0.1.388 — QA-109 Duplicate Material blink color 영구화 fix zip release notes GitHub
핵심 변경
• QA-109 root cause = ApplyMaterialHighlight 의 r.materials 호출 → sharedMaterial 자동 instance 교체 + TickMaterialHighlightPulse emission sin wave 변경 → Instantiate 시점에 blink emission 영구 복사.
• fix: DuplicateCommand.Execute() 안 DuplicateMaterials 직전 ClearMaterialHighlight 호출 + RebuildCacheAndUI 후 HighlightSelectedParts 재호출 (blink 복원).
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs — 5라인 추가 + 4라인 추가 (DuplicateCommand.Execute)
협업자 spec 영향
• QA-109 (Duplicate Material blink color) — root cause 확정 + fix
• QA-110/111/114 — IndicatorManager S0015 통합 path (별도 사이클)
• QA-115 (Unity 6 build cache) — 별개 진단 (cache 문제 아님 = L3952 1줄 fix 완료, v0.1.387 51st seal)

v0.1.387 — v0.1.387 — REAL FIX 완성 — binary search 코드 모두 revert + 정상 async path 복원

v0.1.387 v0.1.387 — REAL FIX 완성 — binary search 코드 모두 revert + 정상 async path 복원 zip release notes GitHub
사용자 보고
• v0.1.384 V384 CLICKED + ClickEvent 토스트 출현 = click event 정상 발화 확정
• 이전 'click 차단' 가설 반박
• v0.1.386 빌드는 L3952 fix만 + binary search 코드 잔존 = StepImportService 호출 안 함
v0.1.387 REAL FIX 완성
• Bootstrap.cs L1735~ cmd-import-step 람다: V384 4 event + if(false) 람다 모두 제거
• 정상 async path 복원: PickStepFile → ConvertStepToGlbAsync → ImportGlbAsync
• L3952 v0.1.332 QA-097 fix revert 유지 (root cause 해결)
검증
• 사용자 PC v0.1.387 zip 실행 → 도구(T) > 모델링 IMPORT click
• 토스트: 'STEP 변환 시작: <파일명>' 출현 의무
• Win32 OpenFileDialog 출현 의무

v0.1.386 — v0.1.386 — REAL ROOT CAUSE FIX — v0.1.332 QA-097 회기 1줄 제거

v0.1.386 v0.1.386 — REAL ROOT CAUSE FIX — v0.1.332 QA-097 회기 1줄 제거 zip release notes GitHub
19 사이클 fix 시도 후 진짜 root cause 확정
• 도구: Mono.Cecil (Unity 동봉) reflection으로 v0.1.331 vs v0.1.332 dll IL 비교
• 결과: Factory00Bootstrap.Update() 단 1 메서드 +19 byte 변경
• 진짜 root cause: Bootstrap.cs L3952 v0.1.332 QA-097 fix
if (!overUI && _lnbActiveIdx >= 0) HideLnbDropdown();
• 결함: IsPointerOverUI()가 cmd-import-step button을 UI로 인식 못 함 → false → HideLnbDropdown 호출 → button click 발화 차단
v0.1.386 fix
• L3952 라인 1개 주석 처리 (revert)
• 대체: L1654 root.RegisterCallback(TrickleDown)가 이미 dropdown 외 click 닫기 처리
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs L3949~3952 (1줄 주석)
검증
• 사용자 PC v0.1.386 zip 실행 → 도구(T) > 모델링 IMPORT click → Win32 OpenFileDialog 출현 의무
• v0.1.331 baseline 동작 회복 확정 (코드 변경은 v0.1.332 회기 1줄만 revert, 다른 v0.1.333~385 모든 추가 기능 보존)

v0.1.385 — v0.1.385 — A안 binary search #4 — RotaryPneumaticActuators LoadProject 분기 비활성

v0.1.385 v0.1.385 — A안 binary search #4 — RotaryPneumaticActuators LoadProject 분기 비활성 zip release notes GitHub
v0.1.382~384 결과
• v0.1.382 Pneumatic 자동 부착 비활성 → dropdown/샘플 회복 + STEP click 잔존
• v0.1.384 4 event 진단 = PointerDown 자체 도달 0 확정
• 추론: v0.1.331 vs v0.1.335 신규 type 2건 (PneumaticRotaryCylinderActuator + PortArrivalSensor)
v0.1.385 A안 fix
• Bootstrap.cs L640~661 RotaryPneumaticActuators LoadProject 분기 #if false
• 사용자 .twn에 RotaryPneumatic 부재이므로 실행 path 0, 그러나 시도 가치
• PortArrivalSensor는 PneumaticCylinderActuator 필드 → 별도 비활성 불가
검증
• 사용자 PC: STEP click 시 V384 토스트 출현 여부

v0.1.384 — v0.1.384 — binary search #3 — button.clicked 차단 가설 진단

v0.1.384 v0.1.384 — binary search #3 — button.clicked 차단 가설 진단 zip release notes GitHub
v0.1.383 결과 (Player_1.log)
• wiring: OK + click 로그 0건 = button.clicked event 자체 차단 확정
v0.1.384 진단
• cmd-import-step button에 4 event 동시 RegisterCallback:
1. button.clicked (기존)
2. ClickEvent (UI Toolkit ClickEvent)
3. PointerDownEvent NoTrickleDown (target phase)
4. PointerDownEvent TrickleDown (capture phase)
• 어느 event가 발화하는지 Player.log로 확정
검증 의무
• 도구(T) > 모델링 IMPORT click 후 Player.log V384 grep
• 'V384 CLICKED' / 'V384 ClickEvent' / 'V384 PointerDown' 출현 여부 확인
• focusable + pickingMode 값도 wiring 로그에 포함

v0.1.383 — v0.1.383 — binary search #2 — cmd-import-step click handler 단순화 (async/StepImportService 제거)

v0.1.383 v0.1.383 — binary search #2 — cmd-import-step click handler 단순화 (async/StepImportService 제거) zip release notes GitHub
진단 path
• v0.1.382 결과: dropdown OK + 샘플 OK + STEP 임포트만 무동작
• 1차 root cause = Pneumatic 자동 부착 (LNB dropdown/Bootstrap 초기화 영향) 확정 (v0.1.382 PASS)
• 잔존 결함 = STEP 임포트 click handler 안 async/StepImportService 또는 UI 자체
v0.1.383 fix
• cmd-import-step.clicked → 단순 Debug.LogError + FlashToast만 (async 제거)
• StepImportService 호출 안 함
• async lambda 원본은 if(false) 분기로 보존 (revert 용이)
검증 의무
• 사용자 PC: 도구(T) > 모델링 IMPORT click
◦ 토스트 'V383 SIMPLE: cmd-import-step click 정상 도달' 출현 = click event 정상 = root cause = async/StepImportService
◦ 토스트 안 나옴 = click event 자체 차단 = LNB system 결함 (다른 path 필요)

v0.1.382 — v0.1.382 — QA-104 binary search #1 — Pneumatic 자동 부착 임시 비활성

v0.1.382 v0.1.382 — QA-104 binary search #1 — Pneumatic 자동 부착 임시 비활성 zip release notes GitHub
진단 path
• v0.1.331 OK / v0.1.335 무동작 + ProjectSettings 가설 반박 = 신규 9 .cs 파일 의심
• 1차 시도: ActuatorDriver.cs L46~55 PneumaticStrokeBarVisualizer 자동 부착 #if false 처리
• 사용자 .twn에 Pneumatic 부재이므로 직접 코드 path 실행 0이지만 type metadata는 dll에 잔존
검증 의무
• 사용자 PC v0.1.382 zip 실행
• 도구(T) > 모델링 IMPORT click 동작 여부
• PASS = Pneumatic 자동 부착이 root cause / FAIL = 다른 9 .cs 파일 path

v0.1.380 — v0.1.380 — QA-104 root cause fix r4 — Unity 6 Bee cache 백업 (진짜 cache invalidate)

v0.1.380 v0.1.380 — QA-104 root cause fix r4 — Unity 6 Bee cache 백업 (진짜 cache invalidate) zip release notes GitHub
진짜 root cause 발견
• Unity 6는 Library/Bee/ 빌드 시스템 사용 (ScriptAssemblies 아님)
• .dag 파일 17:04 시점 그대로 → .cs 변경 감지 실패
• v0.1.367~379 13 사이클 dll byte-for-byte 동일 (488960)
• v0.1.366 dll = 486912 byte (사용자 명시 OK 시점, baseline)
v0.1.380 fix
• Library/Bee → Bee-stale-211938 백업 (mv)
• Library/PlayerDataCache → PlayerDataCache-stale-211938 백업
• Unity 6 Bee build system fresh dependency graph 생성 의무
• target hierarchy 검증 + 진단 LogError 코드 유지
검증 의무
• archive v0.1.379 vs v0.1.380 dll size diff ≠ 0 byte (Bee fresh 빌드 증거)
• 사용자 PC Player.log [lnb-click] 진단 로그 출력 확인
영향 파일
• Library/Bee (~16MB cache 백업)
• Library/PlayerDataCache (~7MB 백업)

v0.1.379 — v0.1.379 — QA-104 root cause fix r3 — Library/ScriptAssemblies 백업 후 강제 재컴파일

v0.1.379 v0.1.379 — QA-104 root cause fix r3 — Library/ScriptAssemblies 백업 후 강제 재컴파일 zip release notes GitHub
사용자 명시 (A안 진행)
• v0.1.377 + v0.1.378 dll byte-for-byte 동일 (Library cache hit)
• ScriptAssemblies → ScriptAssemblies-stale-{HHMMSS} 백업 (mv, rm 차단 회피)
• Unity가 ScriptAssemblies 부재 감지 → 모든 .cs 강제 재컴파일
v0.1.379 fix
• L1657 PointerDown 핸들러: target hierarchy 검증 (worldBound OR Contains)
• L1660 진단 LogError 5변수 (ribbonTgt/ribbonPos/dropTgt/dropPos)
• dll 재컴파일 보장 → 사용자 PC Player.log [lnb-click] 진단 가능
검증 의무
• archive v0.1.378 vs v0.1.379 dll size diff ≠ 0 byte (재컴파일 PASS 증거)
• 사용자 PC 도구(T) > 모델링 IMPORT click → Player.log [lnb-click] 로그 출력 확인

v0.1.378 — v0.1.378 — QA-104 root cause fix r2 — Library cache invalidate + 진단 LogError 추가

v0.1.378 v0.1.378 — QA-104 root cause fix r2 — Library cache invalidate + 진단 LogError 추가 zip release notes GitHub
v0.1.377 빌드 결함 발견
• archive v0.1.376 vs v0.1.377 Assembly-CSharp.dll size diff = 0 byte
• Library/ScriptAssemblies cache hit → 코드 fix 빌드에 미포함
• exe mtime 가드는 PASS 했지만 IL 동일
v0.1.378 fix
• Bootstrap.cs:1657 PointerDown 핸들러에 진단 LogError 추가 (Debug.LogError + 5 변수 검출)
• 의미 있는 코드 추가로 Unity 변경 감지 강제 → dll 재컴파일 보장
• target hierarchy 검증 + worldBound 검증 동시 적용 (v0.1.377 fix 유지)
영향 파일
• Assets/Scripts/Game/Factory00Bootstrap.cs:1657 (8 추가 진단 라인)

v0.1.377 — v0.1.377 — QA-104 root cause fix · LNB PointerDown target hierarchy 검증

v0.1.377 v0.1.377 — QA-104 root cause fix · LNB PointerDown target hierarchy 검증 zip release notes GitHub
사용자 보고 (v0.1.376 Player.log)
[step-import] wiring: OK parent=cmds-tools → wiring 정상
[step-import] click 발화 로그 부재 → click event 차단 확정
• 도구(T) 하위 모든 8 button 동일 무동작 (cmd-import-step / tool-options / review-* / present-* / tool-move-part)
root cause
Factory00Bootstrap.cs:1654 root.RegisterCallback(TrickleDown) 핸들러
activeDropdown.worldBound.Contains(evt.position) 단독 검증 → cmds-tools worldBound 결함 시 false
HideLnbDropdown() 호출 → dropdown display:None 전환 → button click event 발화 차단
• v0.1.367 silent fix가 cmds-tools 위치/크기 계산을 깬 가능성 (회기 도입 시점)
v0.1.377 fix
• target hierarchy 검증 추가 — activeDropdown.Contains(tgt as VisualElement)
• worldBound contains OR target hierarchy contains 둘 중 하나만 PASS → 차단 안 됨
• ribbon-tabs 도 동일 패턴 강건화 (예방적)
• worldBound 결함 무관 → button click event 정상 발화 보장
영향 파일
Assets/Scripts/Game/Factory00Bootstrap.cs:1654 (8 라인 — 7 추가 + 1 코멘트)
검증 의무 (사용자 PC)
• 도구(T) > 모델링 IMPORT click → Win32 OpenFileDialog 출현
• Player.log [step-import] click 발화 로그 출력 확인
• 도구(T) 외 다른 dropdown (cmds-file/edit/view/model/run/help) 동작 회귀 0 확인

v0.1.376 — v0.1.376 — wiring 진단 LogError 2줄만 (silent fix 변경 X)

v0.1.376 v0.1.376 — wiring 진단 LogError 2줄만 (silent fix 변경 X) zip release notes GitHub
사용자 보고
• v0.1.362/375 모두 무동작 + Player.log에 step-import 로그 0건
v0.1.376 진단 fix
• wiring 시점 LogError 무조건 출력 (cmdImportStep null/OK + parent)
• click 발화 시점 LogError 출력
• 사용자 PC Player.log grep step-import → 결과로 root cause 확정 가능

v0.1.375 — v0.1.375 — QA-104 회기 root cause 확정 + v0.1.366 형태 완전 복원

v0.1.375 v0.1.375 — QA-104 회기 root cause 확정 + v0.1.366 형태 완전 복원 zip release notes GitHub
archive dll size diff 근거 (어시스턴트 자가 검증)
• v0.1.361~366: Assembly-CSharp.dll 486912 byte 동일 (사용자 명시 "v0.1.362/363 새벽 01시 동작 OK" 일치)
• v0.1.367: 487424 byte (+512) — silent fix 추가 시점
• v0.1.368~371: +1024 누적
v0.1.375 복원 작업
회기 도입 fix 제거 (v0.1.367~373)
• v0.1.367 silent fix: if (cmdImportStep == null) { LogError } else { Debug.Log + pickingMode = Position + 토스트 + try/catch } ← 회기 도입
• v0.1.368 Ctrl+Shift+I + pickingMode 강제 ← 제거
• v0.1.373 RunStepImportAsync 메서드 추출 + Ctrl+I 단축키 ← 제거
• v0.1.374 BindRibbonExtraCmds 분리 시도 ← 제거
v0.1.366 형태 복원
var cmdImportStep = root.Q
• 인라인 람다 body — PickStepFile → ConvertStepToGlbAsync → ImportGlbAsync → Parts/Graph/foldExpanded/RebuildVisibleParts/AutoFitTarget
• 외부 메서드 호출 0건. wiring 단순.
보존된 유용한 fix (v0.1.369~372)
• StepImportService OFN_NOCHANGEDIR + GetLastWin32Error 진단 (working dir 보호, 안전)
• QA-106 Inspector grace (_lastInspectorInteractionTime + 1.5s + RegisterCallback trickle-down)
• QA-107 cmd-open silent 방지 토스트
• QA-108 SNB 갱신 6 Add 헬퍼 (Servo/Pneumatic/Tower/RotaryPneumatic/RotaryActuator/Sensor)
• QA-105 PartBoundsExclude marker + 3 visualizer 적용
• QA-088 expandAll/collapseAll Rebuild 강화
• QA-112 ListView ghost row delayed Rebuild
• BindRibbonExtraCmds 메서드 유지 (cmdQuit + viewFirstPerson + 후속 cmd-* wiring, 회기 영향 0)
archive 검증 zip
사용자 직접 비교 가능: https://os-file-server.tail2b816d.ts.net/downloads/factory00-windows-x64-v0.1.366-restored.zip
영향 파일
Factory00Bootstrap.cs cmd-import-step 인라인 람다 복원 (~50 라인)
Factory00Bootstrap.cs RunStepImportAsync 메서드 삭제 (~80 라인)
Factory00Bootstrap.cs Ctrl+I 단축키 영역 삭제 (~10 라인)
Stage 2 사용자 PC 검증
1. v0.1.375 zip → factory00.exe
2. 도구(T) > 모델링 IMPORT 클릭 → Win32 파일 다이얼로그 출현
3. wiki/uploads/occt-screw.step 선택 → 변환 ~30초 → 부품 트리 추가
룰 영구화 (재발방지)
.claude/rules/user-says-it-worked-trust-first.md 신규 — 사용자 "잘되던 기능" 즉시 신뢰 의무
feedback_user_says_it_worked_before.md 메모리와 페어

v0.1.372 — v0.1.372 — QA-088 모두펼치기 + QA-112 ListView ghost row fix

v0.1.372 v0.1.372 — QA-088 모두펼치기 + QA-112 ListView ghost row fix zip release notes GitHub
협업자 PM v0.1.371 검증 결과 (handshake 0ae7e62, 17:47 KST 추정)
• PASS QA-105 PM 진단(Visualizer 합집합) 적중 — 본 cap fix 정확
• PASS QA-106 / QA-107 fix 완료
• [!] QA-088 부분 통과 — 모두접기 PASS / 모두펼치기 2~3초 딜레이 FAIL
• FAIL QA-104 재재탈락 — 토스트조차 미표시 = click event 미발화 (Update 폴링 자체 결함 가설)
• FAIL QA-108 재탈락 — S0015 P1 데이터 모델 영역 (사용자 명시 큰 spec)
• 신규: QA-109/110/111/112
v0.1.372 fix
QA-088 모두펼치기 딜레이
expandAllAction RefreshItems → Rebuild 교체 (collapseAll과 일관)
• RefreshItems는 row state 비교로 큰 트리 느림. Rebuild는 단순 재생성
QA-112 ListView 빈 행 더미
• 앱 시작 + 모두접기 시 ghost row 표시
• root cause: UI Toolkit ListView first Rebuild 후 viewport layout 미완료 상태에서 ghost row 그림
• fix: _partList.schedule.Execute(() => Rebuild()).ExecuteLater(0) — 1프레임 delayed 추가 Rebuild로 viewport 완성 후 재갱신
• 적용 2곳: 초기 로드 L3722 + collapseAllAction
미해결 (사용자 결정 또는 추가 진단)
• QA-104: PM "토스트 미표시 = click event 미발화" — 자율 진단 한계 도달. Player.log [step-import] 로그 사용자 PC 직접 검색 필요
• QA-108: S0015 P1 (트리 데이터 모델 영역) — 큰 spec, 사용자 명시 필요
• QA-109/110/111: 다음 cap 진단 (Material instance / Duplicate ghost / Deselect 핸들러)
영향 파일
Factory00Bootstrap.cs ~8라인 (expandAll Rebuild + 2곳 delayed Rebuild)
Stage 2 검증
1. v0.1.372 zip → factory00.exe
2. QA-112: 앱 시작 즉시 → ListView 빈 더미 0건 확인
3. QA-088: 부품 트리 펼친 상태 → 모두접기 → ghost row 0건 + 모두펼치기 → 즉시 갱신 (딜레이 ↓)

v0.1.371 — v0.1.371 — QA-105 Gizmo 오프셋 + QA-088 모두접기 재탈락 fix

v0.1.371 v0.1.371 — QA-105 Gizmo 오프셋 + QA-088 모두접기 재탈락 fix zip release notes GitHub
v0.1.371 핵심 fix
QA-105 Gizmo 위치 오프셋 (PM v0.1.367 회귀 보고)
root cause 확정: Visualizer GameObject가 Part.cachedTransform 자식 → ComputePartBoundsGetComponentsInChildren(true)이 Visualizer mesh 포함 → bounds center 이동 → Gizmo 위치 오프셋
fix: 신규 marker Factory00.Core.PartBoundsExclude (Assets/Scripts/Core/PartBoundsExclude.cs, 5라인) + ComputePartBounds 안 GetComponentInParent() != null skip 가드
적용 위치 3건:
ActuatorDriver.cs L48 (PneumaticStrokeBar visualizer)
Sensors/PhotoSensorVisualizer.cs L55 (LineRenderer cone)
Actuators/PneumaticStrokeBarVisualizer.cs L79 (LineRenderer bar)
QA-088 모두접기 v0.1.367 재탈락 fix
root cause: v0.1.358 fix RefreshItems() 만 호출 → ListView row의 bindItem이 cached _foldExpanded state 사용 → fold triangle (▸/▾) visual 갱신 안 됨
fix: RefreshItems()Rebuild() 교체 (모든 row 재생성으로 fold triangle 강제 재렌더)
영향 파일
Assets/Scripts/Core/PartBoundsExclude.cs 신규 (5라인)
Factory00Bootstrap.cs ComputePartBounds skip 가드 + collapseAllAction Rebuild (~6라인)
ActuatorDriver.cs + PhotoSensorVisualizer.cs + PneumaticStrokeBarVisualizer.cs AddComponent 3건 (3라인)
Stage 2 검증 (사용자/PM PC)
1. v0.1.371 zip → factory00.exe
2. QA-105: 부품 선택 → 부품/컴포넌트 > Add Sensor (또는 Pneumatic) → Gizmo 위치 정합 확인 (오프셋 0)
3. QA-088: 부품 트리 펼친 상태 → 부품 리스트 헤더 모두접기 click → 트리 즉시 collapse + 토스트

v0.1.370 — v0.1.370 — QA-108 SNB 갱신 일괄 fix (6 Add 헬퍼)

v0.1.370 v0.1.370 — QA-108 SNB 갱신 일괄 fix (6 Add 헬퍼) zip release notes GitHub
협업자 PM v0.1.367/v0.1.369 보고 (handshake INDEX)
• QA-108 컴포넌트 추가 시 SNB(좌측 부품 트리) 미갱신
• QA-105 Gizmo 위치 오프셋 (다음 사이클 진단 예약)
v0.1.370 fix
QA-108 — 6 Add 헬퍼 끝에 SNB 갱신 추가
AddServoAxisToPart — RebuildVisibleParts + _partList.Rebuild()
AddPneumaticToPart — 동일
AddTowerLampToPart — 동일
AddRotaryPneumaticToPart — 동일
AddRotaryActuatorToPart — 동일
AddPhotoSensorToPart — 동일
• 각 helper 끝 4라인 추가 — 부품 트리에 컴포넌트 배지/상태 즉시 반영
QA-105 보류 — 다음 사이클 (v0.1.371) 진단
• 컴포넌트 추가된 오브젝트 Gizmo 위치 오프셋
• 가능성: visualizer mesh가 Part.cachedTransform Bounds center 변경 → _gizmoCenter 재계산 결함
• 또는 컴포넌트 child GameObject가 Part raycast에 잡혀 잘못된 hit point
영향 파일
Factory00Bootstrap.cs 6 위치 (~24라인 추가)
Stage 2 검증 (사용자/PM PC)
1. v0.1.370 zip → factory00.exe
2. 부품 선택 → 부품/컴포넌트 메뉴 > Add Sensor (또는 Servo/Pneumatic)
3. 부품 트리 좌측 패널 즉시 갱신 확인 (NEW 배지 또는 컴포넌트 마크)

v0.1.369 — v0.1.369 — QA-104+106+107 fix 일괄 (PM v0.1.367 회귀 보고)

v0.1.369 v0.1.369 — QA-104+106+107 fix 일괄 (PM v0.1.367 회귀 보고) zip release notes GitHub
협업자 PM v0.1.367 회귀 보고 (handshake QA-104~107)
• QA-104 STEP 임포트 토스트 미표시 확정 (PM commit 9b40027 16:18)
• QA-106 Inspector 키 입력 + 드롭다운 자동 닫힘 (QA-036/037 회귀)
• QA-107 File→New 후 Open 먹통 (QA-044 회귀)
v0.1.369 fix
QA-104 PickStepFile flags + 진단 (StepImportService.cs L62~)
OFN_NOCHANGEDIR (0x00000008) 추가 — working dir 변경 차단 (다른 dialog 영향 회피)
• GetLastWin32Error 로깅 — 호출 실패 시 err 코드 출력
• NativeFileDialog와 동일 flag SSOT 정합
QA-106 Inspector interaction grace (Bootstrap.cs L487~ + L5200~)
_lastInspectorInteractionTime + 1.5s grace — DropdownField popup focusController 미포착 회귀 안전망
• RegisterCallback trickle-down: KeyDownEvent + ChangeEvent + PointerDownEvent
• 가드 강화: !IsInspectorEditFocused && !IsInspectorRecentlyInteracted 둘 다 충족 시 RenderInspector
QA-107 cmd-open silent 방지 (Bootstrap.cs L2686~)
• click 시점 토스트 "Open 다이얼로그 여는 중..." (Win32 호출 검증)
• try/catch + 에러 토스트
• null wiring 검증 — Debug.LogError
영향 파일
Factory00Bootstrap.cs ~35라인 (Inspector grace + Open silent + Ctrl+Shift+I 우회)
Factory00Bootstrap.cs v0.1.368 cmd-import-step null 가드 + Ctrl+Shift+I 우회 (v0.1.367 silent fix 후속)
Importers/StepImportService.cs 5라인 (PickStepFile flags + 진단)
QA-105 (Gizmo 오프셋) 보류
• root cause 별개 — Pivot 계산 또는 Gizmo target Transform mismatch
• 다음 사이클 (v0.1.370) 진단 예정
Stage 2 검증 (사용자/PM PC)
1. v0.1.369 zip → factory00.exe
2. QA-104: 도구(T) > 모델링 IMPORT 클릭 → 토스트 "STEP 파일 선택 다이얼로그 여는 중..." + 다이얼로그 OR Ctrl+Shift+I 우회 단축키
3. QA-106: 부품 선택 → Inspector 안 TextField 클릭 → 키 입력 → focus 유지 + 입력 가능 확인
4. QA-107: File→New → File→Open 클릭 → 토스트 "Open 다이얼로그 여는 중..." + 다이얼로그

v0.1.368 — v0.1.368 — STEP 임포트 우회 단축키 + z-order 안전망 (QA-104 협업자 PM 보고)

v0.1.368 v0.1.368 — STEP 임포트 우회 단축키 + z-order 안전망 (QA-104 협업자 PM 보고) zip release notes GitHub
협업자 PM 보고 (2026-05-24, handshake QA-104~107)
• QA-104 [P0] STEP 임포트 v0.1.367 silent fix 후에도 전체 무동작 (토스트 표시 여부 확인 필요)
• QA-105 [P0] 컴포넌트 추가된 오브젝트 Gizmo 위치 오프셋 (v0.1.367 회귀)
• QA-106 [P0] Inspector 키 입력 + 드롭다운 자동 닫힘 (QA-036/037 회귀)
• QA-107 [P0] File→New 후 Open 먹통 (QA-044 회귀)
v0.1.368 핵심 fix (QA-104 우선)
z-order 안전망cmdImportStep.pickingMode = PickingMode.Position 강제
진단 로그 추가 — wiring OK 시 pickingMode + enabledInHierarchy 출력
Ctrl+Shift+I 우회 단축키cmds-tools dropdown 안 click 발화 안 되어도 직접 import 호출
◦ 가설: dropdown 안 button click 자체 발화 안 됨 → 단축키로 wiring 검증
◦ reflection으로 Button.clicked Action invoke (UI Toolkit Button 직접 호출)
◦ 사용자 검증 procedure: zip 다운로드 → factory00.exe → Ctrl+Shift+I 직접 시도 → 토스트 + 다이얼로그 확인
QA-105/106/107 — 다음 사이클 (cap 진행)
• v0.1.369 QA-106 Inspector focus 회귀 (RenderInspector 분석)
• v0.1.370 QA-107 File→New 후 Open 회귀 (QA-104와 공통 root cause 가설 검증)
• v0.1.371 QA-105 Gizmo 위치 오프셋 (Pivot 계산)
영향 파일
Factory00Bootstrap.cs L1717~1740 (cmd-import-step 안전망) + L4150~4170 (Ctrl+Shift+I 단축키) ~25라인
Stage 2 검증
1. v0.1.368 zip 다운로드 + factory00.exe 실행
2. Ctrl+Shift+I 직접 시도 → 토스트 "STEP 임포트 (Ctrl+Shift+I 우회)" 출현 + Win32 다이얼로그
3. 그 후 도구(T) > 모델링 IMPORT 클릭 → 토스트 출현 여부 비교
4. 결과 분기:
- Ctrl+Shift+I OK + dropdown click OK → silent fix 자체로 해결 (옛 zip 가설 확정)
- Ctrl+Shift+I OK + dropdown click 실패 → dropdown click 결함 확정 (다음 사이클 깊은 root cause)
- Ctrl+Shift+I 실패 → Player.log 안 [step-import] 검색 → wiring 또는 reflection 실패

v0.1.367 — v0.1.367 — STEP 임포트 silent 회귀 진단 + fix (사용자 보고)

v0.1.367 v0.1.367 — STEP 임포트 silent 회귀 진단 + fix (사용자 보고) zip release notes GitHub
사용자 보고 (2026-05-24)
• "임포트 버튼 눌러도 아무 반응이 없다. 기능 동작 안함."
root cause 후보
• v0.1.367 진단 — cmd-import-step Button wiring 실패 시 silent (Bootstrap.cs L1719 if (cmdImportStep != null) 가드만 있었음)
• 룰 silent-button-toast.md 위반 — listener wiring 실패 또는 PickStepFile 호출 자체 실패 시 사용자에게 아무 피드백 없음
fix
cmd-import-step null 가드Debug.LogError 출력으로 wiring 실패 진단 가능
클릭 시점 토스트 — "STEP 파일 선택 다이얼로그 여는 중..." (click 발화 자체 검증)
PickStepFile try/catch — Win32 PInvoke 실패 시 토스트 + 에러 로그
Debug.Log "[step-import] click 발화" — Player.log 진단
영향 파일
Factory00Bootstrap.cs L1717~1736 (~15라인 추가)
Stage 2 검증 (사용자 PC)
1. v0.1.367 zip 받기 (외부 URL)
2. 압축 해제 → factory00.exe 실행
3. 도구(T) 메뉴 클릭 → "모델링 IMPORT (Step/glTF)" 클릭
4. 기대: "STEP 파일 선택 다이얼로그 여는 중..." 토스트 + Win32 다이얼로그 출현
5. 토스트 안 뜨면: Player.log (%APPDATA%/../LocalLow/factory00/factory00/Player.log) 안 [step-import] 로그 검색
- "[step-import] cmd-import-step Button wiring 실패" 발견 → UXML/panel mount 결함 확정
- "[step-import] click 발화" 발견 + 다이얼로그 안 떠 → Win32 PInvoke 또는 다이얼로그 hidden behind window 결함
빌드 노트 갱신 hook 검증
• publish-build-auto.sh §1.5 stale 가드 첫 작동 — build-title.txt 1번째 줄 v0.1.367 토큰 일치 시 PASS
• §5.5 release-notes 자동 생성 — wiki/topics/release-notes/v0.1.367.md 신규

v0.1.366 — QA-100 sed lazy bug hotfix + 48th stable seal

v0.1.366 QA-100 sed lazy bug hotfix + 48th stable seal zip release notes GitHub
핵심 fix
• v0.1.363 sed 패턴 결함 — group 2 안 lazy [^&]*? 가 0 길이 매칭 → 본문 손실
• v0.1.366 fix — pm-fetched-at div 본문 통째 치환 패턴 (re.DOTALL + lambda group 1+3 preserve)
• 라벨 직접 복구 — handoff-pm-action.html line 162 정확 형식 복원
48th stable seal
• v0.1.298~366 자율 69 사이클 일괄 봉인 (2026-05-22~24)
• 봉인 alias: factory00-windows-x64-v0.1.366-stable.zip (170MB)
• journal: wiki/journal/2026-05-24-v0.1.298-366-48th-stable-seal.md

v0.1.365 — QA-090 T-4 Vertex 스냅 deferred 결정 (GLTFast mesh.isReadable 한계)

v0.1.365 QA-090 T-4 Vertex 스냅 deferred 결정 (GLTFast mesh.isReadable 한계) zip release notes GitHub
결정
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 구현 deferred
• 우회: mesh.MarkDynamic + Mesh.RecalculateBounds 후 vertices 접근 → 일부 GLTF에서 작동
• 결정: Stage 1 deferred, T-1/T-2/T-3/T-5 만으로 QA-090 통합 봉인
영향 파일
• 결정 docs only — 코드 변경 없음

v0.1.364 — QA-101 MxBridge 4섹션 답변 (A.구조/B.메시지포맷/C.배포/D.Mock)

v0.1.364 QA-101 MxBridge 4섹션 답변 (A.구조/B.메시지포맷/C.배포/D.Mock) zip release notes GitHub
핵심 답변
• A. 구조: MxBridgeClient.cs 정확 인용 (TcpClient + json line protocol)
• B. 메시지 포맷: { "op":"read", "area":"D", "addr":100, "count":10 }
• C. 배포: factory00.exe 사용자 PC + mxbridge.exe 별도 host
• D. Mock: UseMock=true 시 메모리 dict 응답 (실 PLC 없이 검증 가능)
영향 파일
• 코드 변경 없음 — 답변만 (handoff [3] 답변 카드)

v0.1.363 — sed 패턴 fix attempt (정규식 lazy bug → v0.1.366에서 hotfix)

v0.1.363 sed 패턴 fix attempt (정규식 lazy bug → v0.1.366에서 hotfix) zip release notes GitHub
사이클 분류
• v0.1.362 sed 패턴이 lazy 매칭 결함 → 본문 손실 발견
• v0.1.363 fix attempt — 부분 해결 (여전히 group 손실)
• v0.1.366에서 최종 hotfix

v0.1.362 — QA-100 handoff 라벨 (pm-fetched-at div + sed 패턴)

v0.1.362 QA-100 handoff 라벨 (pm-fetched-at div + sed 패턴) zip release notes GitHub
핵심 구현
• handoff-pm-action.html line 162: 새 div class="pm-fetched-at"
• publish-build-auto.sh §6.4.5 sed 패턴 추가 (협업자 fetch 시각 자동 갱신)
영향 파일
wiki/handoff-pm-action.html — pm-fetched-at div 신규
Tools/qa/publish-build-auto.sh — sed 패턴 추가

v0.1.361 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.361 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.360 — QA-010 .twn Transform 직렬화 (position/rotation/scale 동기)

v0.1.360 QA-010 .twn Transform 직렬화 (position/rotation/scale 동기) zip release notes GitHub
핵심 구현
• SaveProject foreach Part cachedTransform → position/rotation/scale 동기
• LoadProject 복원 추가
• scale fallback (Vector3.zero → Vector3.one)
• File→New ClearImportedScene 신설
영향 파일
ProjectIO.cs — Save/Load Transform 직렬화
Factory00Bootstrap.cs — File→New ClearImportedScene

v0.1.359 — QA-021 Duplicate 보강 (RotaryPneumatic + ResetPlcBinding)

v0.1.359 QA-021 Duplicate 보강 (RotaryPneumatic + ResetPlcBinding) zip release notes GitHub
핵심 fix
• DuplicateRotaryPneumaticActuators 신규 (v0.1.335 누락 fix)
• ResetActuatorPlcBinding 본문 (Linear+Rotary 공통 헬퍼)
영향 파일
Factory00Bootstrap.cs — DuplicateRotaryPneumaticActuators + ResetActuatorPlcBinding

v0.1.358 — QA-088 모두접기 fix (5라인 hotfix)

v0.1.358 QA-088 모두접기 fix (5라인 hotfix) zip release notes GitHub
핵심 fix
• collapseAllAction InitFoldDefaults 호출이 fold state 리셋 안 함
• fix: foreach _foldExpanded[id]=false (5라인)
영향 파일
Factory00Bootstrap.cs — collapseAllAction 5라인 hotfix

v0.1.357 — QA-030 부품 리스트 필터링 P2 (PartFilterMode 5종 + F4~F8)

v0.1.357 QA-030 부품 리스트 필터링 P2 (PartFilterMode 5종 + F4~F8) zip release notes GitHub
핵심 구현
• PartFilterMode enum 5종: All / Visible / Hidden / Sensors / Actuators
• F4~F8 단축키 (F4=All, F5=Visible, F6=Hidden, F7=Sensors, F8=Actuators)
• [▼필터] 드롭다운 — 부품 리스트 패널 헤더
영향 파일
Factory00Bootstrap.cs — PartFilterMode + ApplyPartFilter
MainHUD.uxml — [▼필터] 드롭다운 추가

v0.1.356 — QA-030 부품 리스트 필터링 P2 (PartFilterMode 5종 + F4~F8)

v0.1.356 QA-030 부품 리스트 필터링 P2 (PartFilterMode 5종 + F4~F8) zip release notes GitHub
핵심 구현
• PartFilterMode enum 5종: All / Visible / Hidden / Sensors / Actuators
• F4~F8 단축키 (F4=All, F5=Visible, F6=Hidden, F7=Sensors, F8=Actuators)
• [▼필터] 드롭다운 — 부품 리스트 패널 헤더
영향 파일
Factory00Bootstrap.cs — PartFilterMode + ApplyPartFilter
MainHUD.uxml — [▼필터] 드롭다운 추가

v0.1.355 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.355 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.354 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.354 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.353 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.353 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.352 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.352 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.351 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.351 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.350 — QA-099 RotaryAxis rename 답변 (코스메틱)

v0.1.350 QA-099 RotaryAxis rename 답변 (코스메틱) zip release notes GitHub
핵심
• 협업자 PM QA-099 RotaryAxis rename 요청 답변 (코스메틱)
• 구현 안 함 — 답변만 (rename 영향 분석)

v0.1.349 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.349 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.348 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.348 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.347 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.347 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.346 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.346 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.345 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.345 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.343 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.343 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.342 — QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적)

v0.1.342 QA-090 Measure/Angle/Collision 씬 오버레이 (P1~P5 누적) zip release notes GitHub
사이클 (v0.1.342~365 24 사이클 누적)
• T-1: LineRenderer로 측정 결과 선 그리기
• T-2: TMP World Space 라벨 (거리 / 각도 / 충돌 부품명)
• T-3: SceneSelectionHandler 모드 (측정 → 점-점 / 각도 → 점-점-점 / 충돌 → AABB)
• T-5: BBox 26 스냅 포인트 (모서리 8 + 모서리 중점 12 + 면 중점 6)
잔존 (deferred)
• T-4 Vertex 스냅 = GLTFast mesh.isReadable=false 한계로 deferred
봉인
• 48th stable seal (v0.1.366) 2026-05-24 일괄

v0.1.341 — 잡 사이클 — Visualizer/RotaryPneumatic 후속 polish

v0.1.341 잡 사이클 — Visualizer/RotaryPneumatic 후속 polish zip release notes GitHub
분류
• v0.1.334+339 PneumaticStrokeBarVisualizer P1 후속
• 48th seal 일괄 봉인 (v0.1.366) 참조

v0.1.340 — 잡 사이클 — Visualizer/RotaryPneumatic 후속 polish

v0.1.340 잡 사이클 — Visualizer/RotaryPneumatic 후속 polish zip release notes GitHub
분류
• v0.1.334+339 PneumaticStrokeBarVisualizer P1 후속
• 48th seal 일괄 봉인 (v0.1.366) 참조

v0.1.339 — PneumaticStrokeBarVisualizer P1 (스트로크 진행률 막대 시각화)

v0.1.339 PneumaticStrokeBarVisualizer P1 (스트로크 진행률 막대 시각화) zip release notes GitHub
핵심 구현
• Pneumatic actuator stroke 진행률을 화면에 막대로 표시
• Position [0.0, 1.0] → bar width 매핑
• TMP World Space 라벨 (현재 위치 % 표시)
시각 검증
• 후속 봉인 (48th seal) 캡처에서 stroke 막대 확인 가능

v0.1.338 — 잡 사이클 — RotaryPneumatic 후속 polish

v0.1.338 잡 사이클 — RotaryPneumatic 후속 polish zip release notes GitHub
분류
• v0.1.335~336 RotaryPneumaticActuator P1 후속
• 48th seal 일괄 봉인 (v0.1.366) 참조

v0.1.337 — 잡 사이클 — RotaryPneumatic 후속 polish

v0.1.337 잡 사이클 — RotaryPneumatic 후속 polish zip release notes GitHub
분류
• v0.1.335~336 RotaryPneumaticActuator P1 후속
• 48th seal 일괄 봉인 (v0.1.366) 참조

v0.1.336 — RotaryPneumaticActuator P1 (회전형 공압 액추에이터)

v0.1.336 RotaryPneumaticActuator P1 (회전형 공압 액추에이터) zip release notes GitHub
핵심 구현
• 회전형 공압 (PneumaticActuator 회전 변종)
• 각도 기반 state machine (Open 위치 = X°, Closed 위치 = Y°)
• PneumaticPlcBridge 회전 분기 (CoilOpen/CoilClose → 각도 명령)
잔존 (v0.1.359에서 fix)
• Duplicate 미지원 → v0.1.359 DuplicateRotaryPneumaticActuators 신규

v0.1.335 — RotaryPneumaticActuator P1 (회전형 공압 액추에이터)

v0.1.335 RotaryPneumaticActuator P1 (회전형 공압 액추에이터) zip release notes GitHub
핵심 구현
• 회전형 공압 (PneumaticActuator 회전 변종)
• 각도 기반 state machine (Open 위치 = X°, Closed 위치 = Y°)
• PneumaticPlcBridge 회전 분기 (CoilOpen/CoilClose → 각도 명령)
잔존 (v0.1.359에서 fix)
• Duplicate 미지원 → v0.1.359 DuplicateRotaryPneumaticActuators 신규

v0.1.334 — PneumaticStrokeBarVisualizer P1 (스트로크 진행률 막대 시각화)

v0.1.334 PneumaticStrokeBarVisualizer P1 (스트로크 진행률 막대 시각화) zip release notes GitHub
핵심 구현
• Pneumatic actuator stroke 진행률을 화면에 막대로 표시
• Position [0.0, 1.0] → bar width 매핑
• TMP World Space 라벨 (현재 위치 % 표시)
시각 검증
• 후속 봉인 (48th seal) 캡처에서 stroke 막대 확인 가능

v0.1.333 — QA-093 E-Stop hotfix (S0002 r003) — EStop state 폐지 + Held → Stopped

v0.1.333 QA-093 E-Stop hotfix (S0002 r003) — EStop state 폐지 + Held → Stopped zip release notes GitHub
핵심 변경
• EStop state 폐지 + Held → Stopped 통합 (enum 6→5)
• CoilEStop → CoilStop rename
• PneumaticEStopEvent → PneumaticStoppedEvent
• .twn 자동 마이그레이션 (옛 EStop 토큰 → Stopped 변환)
영향 파일 (6)
PneumaticActuator.cs — state machine 단순화
PneumaticPlcBridge.cs — CoilEStop → CoilStop
Factory00Bootstrap.cs — UI 라벨 갱신
.twn 자동 마이그레이션 로직

v0.1.332 — 잡 사이클 (handoff 추적 안 됨)

v0.1.332 잡 사이클 (handoff 추적 안 됨) zip release notes GitHub
분류
• 자율 모드 사이클 — build-title 미갱신
• 48th seal 일괄 봉인 (v0.1.366) 참조

v0.1.331 — S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded)

v0.1.331 S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded) zip release notes GitHub
사이클 (7 사이클 누적)
• v0.1.325: StepImportService 신규 (Win32 OpenFileDialog + subprocess + GltfImport)
• v0.1.326~329: cadquery-ocp + Python embedded 패키징 (411MB)
• v0.1.330~331: 회기 검증 MD5 hash 일치 + 빌드 zip 동봉
영향 파일
Assets/Scripts/Importers/StepImportService.cs 신규 (~130라인)
Factory00Bootstrap.cs — cmd-import-step 핸들러 wiring
Tools/converter-py-slim/ — Python 3.11.9 embedded + cadquery-ocp
Stage 2 검증
• 도구(T) > 모델링 IMPORT 클릭 → wiki/uploads/occt-screw.step 선택
• ~30초 대기 → 부품 트리 새 항목 추가 확인

v0.1.330 — S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded)

v0.1.330 S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded) zip release notes GitHub
사이클 (7 사이클 누적)
• v0.1.325: StepImportService 신규 (Win32 OpenFileDialog + subprocess + GltfImport)
• v0.1.326~329: cadquery-ocp + Python embedded 패키징 (411MB)
• v0.1.330~331: 회기 검증 MD5 hash 일치 + 빌드 zip 동봉
영향 파일
Assets/Scripts/Importers/StepImportService.cs 신규 (~130라인)
Factory00Bootstrap.cs — cmd-import-step 핸들러 wiring
Tools/converter-py-slim/ — Python 3.11.9 embedded + cadquery-ocp
Stage 2 검증
• 도구(T) > 모델링 IMPORT 클릭 → wiki/uploads/occt-screw.step 선택
• ~30초 대기 → 부품 트리 새 항목 추가 확인

v0.1.329 — S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded)

v0.1.329 S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded) zip release notes GitHub
사이클 (7 사이클 누적)
• v0.1.325: StepImportService 신규 (Win32 OpenFileDialog + subprocess + GltfImport)
• v0.1.326~329: cadquery-ocp + Python embedded 패키징 (411MB)
• v0.1.330~331: 회기 검증 MD5 hash 일치 + 빌드 zip 동봉
영향 파일
Assets/Scripts/Importers/StepImportService.cs 신규 (~130라인)
Factory00Bootstrap.cs — cmd-import-step 핸들러 wiring
Tools/converter-py-slim/ — Python 3.11.9 embedded + cadquery-ocp
Stage 2 검증
• 도구(T) > 모델링 IMPORT 클릭 → wiki/uploads/occt-screw.step 선택
• ~30초 대기 → 부품 트리 새 항목 추가 확인

v0.1.328 — S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded)

v0.1.328 S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded) zip release notes GitHub
사이클 (7 사이클 누적)
• v0.1.325: StepImportService 신규 (Win32 OpenFileDialog + subprocess + GltfImport)
• v0.1.326~329: cadquery-ocp + Python embedded 패키징 (411MB)
• v0.1.330~331: 회기 검증 MD5 hash 일치 + 빌드 zip 동봉
영향 파일
Assets/Scripts/Importers/StepImportService.cs 신규 (~130라인)
Factory00Bootstrap.cs — cmd-import-step 핸들러 wiring
Tools/converter-py-slim/ — Python 3.11.9 embedded + cadquery-ocp
Stage 2 검증
• 도구(T) > 모델링 IMPORT 클릭 → wiki/uploads/occt-screw.step 선택
• ~30초 대기 → 부품 트리 새 항목 추가 확인

v0.1.327 — S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded)

v0.1.327 S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded) zip release notes GitHub
사이클 (7 사이클 누적)
• v0.1.325: StepImportService 신규 (Win32 OpenFileDialog + subprocess + GltfImport)
• v0.1.326~329: cadquery-ocp + Python embedded 패키징 (411MB)
• v0.1.330~331: 회기 검증 MD5 hash 일치 + 빌드 zip 동봉
영향 파일
Assets/Scripts/Importers/StepImportService.cs 신규 (~130라인)
Factory00Bootstrap.cs — cmd-import-step 핸들러 wiring
Tools/converter-py-slim/ — Python 3.11.9 embedded + cadquery-ocp
Stage 2 검증
• 도구(T) > 모델링 IMPORT 클릭 → wiki/uploads/occt-screw.step 선택
• ~30초 대기 → 부품 트리 새 항목 추가 확인

v0.1.326 — S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded)

v0.1.326 S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded) zip release notes GitHub

v0.1.325 — S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded)

v0.1.325 S0051 STEP 임포트 PoC (cadquery-ocp 7.9.3 + Python 3.11.9 embedded) zip release notes GitHub
사이클 (7 사이클 누적)
• v0.1.325: StepImportService 신규 (Win32 OpenFileDialog + subprocess + GltfImport)
• v0.1.326~329: cadquery-ocp + Python embedded 패키징 (411MB)
• v0.1.330~331: 회기 검증 MD5 hash 일치 + 빌드 zip 동봉
영향 파일
Assets/Scripts/Importers/StepImportService.cs 신규 (~130라인)
Factory00Bootstrap.cs — cmd-import-step 핸들러 wiring
Tools/converter-py-slim/ — Python 3.11.9 embedded + cadquery-ocp
Stage 2 검증
• 도구(T) > 모델링 IMPORT 클릭 → wiki/uploads/occt-screw.step 선택
• ~30초 대기 → 부품 트리 새 항목 추가 확인

v0.1.324 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.324 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.323 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.323 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.322 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.322 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.321 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.321 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.320 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.320 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.319 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.319 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.318 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.318 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.317 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.317 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.316 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.316 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.315 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.315 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.314 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.314 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.313 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.313 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.312 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.312 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.309 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.309 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.308 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.308 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.307 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.307 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.306 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.306 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.305 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.305 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.304 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.304 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.303 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.303 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.302 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.302 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.301 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.301 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.300 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.300 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.299 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.299 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.298 — 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector)

v0.1.298 협업자 spec P1/P2 진행 (tower-lamp / studio-hamburger-lnb / Edit / Inspector) zip release notes GitHub
사이클 분류
• 47th seal (v0.1.297) 이후 자율 모드 P1/P2 점진 누적
• build-title.txt 매 사이클 갱신 안 되어 세부 추적 불가
• 정확한 분기 = handoff-pm-action.html [3] 답변 카드 + 48th seal journal 참조
본 사이클 영역
• tower-lamp P1.1~1.3 (데이터/Inspector/Bridge+Emission)
• studio-hamburger-lnb P1.x (사전 검토 분석 + 미니 리본)
• Edit/Inspector 후속 polish
봉인 정보
• 일괄 봉인: 48th stable seal (v0.1.366) 2026-05-24
• release notes: v0.1.366.md 통합 참조

v0.1.297 — v0.1.297 MX Component P1.1~P1.7 mock 100% + hamburger-lnb P1.4 AppQuit

v0.1.297 v0.1.297 MX Component P1.1~P1.7 mock 100% + hamburger-lnb P1.4 AppQuit zip release notes GitHub
사이클 요약
자율 모드 ~7.5h (사이클 47~83) 누적 — 협업자 spec 4건 100% (panel-resize-pin + tower-lamp + edit-copy-cut-paste + MX mock) + hamburger-lnb P1.4 부분.
MX Component (Tier C-1 QA-074) P1.1~P1.7
• IMitsubishiDriver 인터페이스 (65라인)
• PlcEvents 5종 readonly struct (128라인)
• PlcDeviceMap + 연속 그룹핑 (140라인)
• MxBridgeClient TCP + mock 6명령 (243라인)
• MitsubishiPlcDriverComponent MonoBehaviour 폴링 (273라인)
• MitsubishiPlcDriverPanel Inspector UI (287라인)
mock 모드 default — MitsubishiPlcDriverComponent.UseMock=true. SDK 부재 빌드/실행 가능. SDK 도착 후 UseMock=false 1줄 전환.
hamburger-lnb P1.4 (자율 부분)
• AppQuitCommandEvent.cs 신규 (35라인 readonly struct)
• EventBus.cs +8라인 (event + Publish + Reset null)
• Factory00Bootstrap.cs +12라인 (Awake 자체 구독자 + ExitAfterDelay 전환)
• 협업자 spec brief import (154라인)
• Q-1~Q-7 7건 모두 A안 확정
통합
• Bootstrap +30 (MX 자동 부착 + AppQuit + OnDestroy Unsubscribe)
• Ribbon.uxml +1 버튼 (comm-mitsubishi-mx-inspector)
• EventBus +20 (Plc 5종 + AppQuit 1종 + Reset null)
critic
3 라운드 PASS — 사이클 50/57/59. 치명 2 + 중대 8 + 중간 6 + 사소 4 모두 fix.
SSOT 인프라
wiki/latest-version.js 신규 — 3 페이지 단일 SSOT
• publish-build-auto.sh 6.9 hook — 매 빌드 자동 갱신
/bump-version 스킬 latest-version.js 통합
• 룰 latest-version-ssot.md 신규

v0.1.290 — v0.1.290 silent-button audit fix + component-scene-inspector 사전 분석 진행

v0.1.290 v0.1.290 silent-button audit fix + component-scene-inspector 사전 분석 진행 zip release notes GitHub
사이클 요약
자율 audit 후속 작은 fix — silent-button-toast.md 룰 위반 1건 (구동부 +추가 비활성 버튼) 정상화. 동시에 component-scene-inspector-ux 사전 분석 docs 진행 예약.
변경
| 영역 | 변경 | 라인 |
|---|---|---|
| Factory00Bootstrap.cs:5763 disBtn | SetEnabled(false) 제거 + opacity = 0.55f (시각 비활성) + 토스트 메시지 명확화 | +2 -1 |
라인 합계: ~3. 매우 작은 fix.
silent-button-toast.md 룰 준수
| 항목 | before | after |
|---|---|---|
| interactable | [X] false (클릭 차단) | [완료] true (listener 활성) |
| 클릭 시 동작 | [!] 무반응 | [완료] 토스트 "구동부는 부품당 1개 (이미 부착됨)" |
| 시각 비활성 표시 | SetEnabled(false) | opacity 0.55f |
audit 누적
| 룰 위반 | 발견 | 처리 |
|---|---|---|
| silent-button #1 (disBtn 구동부) | v0.1.286 cycle audit | [완료] v0.1.290 |
| silent-button #2 (edit-cut) | v0.1.288 critic | [완료] v0.1.289 |
silent-button-toast.md 룰 위반 0건 (factory00 워크스페이스 전수).
다음 자율 사이클
- v0.1.291 docs-only: component-scene-inspector-ux 사전 분석
- 또는 45th seal 봉인 (v0.1.289~290 2 사이클 누적 — 작은 cadence)

v0.1.289 — v0.1.289 edit-copy-cut-paste P3 — Cut (Ctrl+X) 옵션 B 구현

v0.1.289 v0.1.289 edit-copy-cut-paste P3 — Cut (Ctrl+X) 옵션 B 구현 zip release notes GitHub
사이클 요약
자율 모드 사전 분석 (wiki/topics/edit-cut-snapshot-options.md) 기반 옵션 B 채택. DeleteCommand 가 SetActive(false) 패턴이라 cachedTransform 살아있음 -> DuplicateCommand 안 Instantiate 정상 동작. 추가 SetActive(true) 1줄로 Cut 후 Paste 시 새 GameObject active 보장.
변경
| 영역 | 변경 | 라인 |
|---|---|---|
| Ctrl+X 단축키 (Update KeyDown) | KeyCode.X -> CutSelected() | +1 |
| CutSelected 메서드 | Copy + DeleteSelectedPart 직렬 호출 + 토스트 | +18 |
| Edit 탭 edit-cut 활성화 | silent-button listener -> CutSelected() 호출 | -2 +3 |
| DuplicateCommand SetActive(true) | Cut 후 Paste 시 inactive 상속 회피 | +2 |
| 우클릭 메뉴 "잘라내기" 항목 | BuildObjectMenuItems Copy 옆 추가 | +14 |
라인 합계: ~36. 1000라인 한도 안전.
동작 시나리오
`
[선택 N] -> Ctrl+X (또는 Edit 탭 Cut)
① CopySelected — _clipboard 에 참조 N개 보관
② DeleteSelectedPart — DeleteCommand IEditCommand -> UndoStack push
각 부품 cachedTransform.gameObject.SetActive(false) + _partHidden[id]=true
Parts list 잔존, cachedTransform null 아님
③ FlashToast: "Cut: N개 잘라내기 (Ctrl+V 새 위치 / Ctrl+Z 원본 복원)"
-> Ctrl+V (새 위치 또는 그 자리)
각 _clipboard Part 마다 DuplicateCommand
Instantiate(origGo) — origGo inactive 여도 transform 정상 -> 새 GameObject 생성
SetActive(true) 명시 호출 — Cut 케이스 대응
+50mm 오프셋 (origId 누적 카운터)
Material 복사 (QA-021 정책) / 컴포넌트 / 자식 hierarchy 모두 자동
-> Ctrl+Z (Paste undo, N번)
각 DuplicateCommand undo — 새 GameObject SetActive(false) + Parts.Remove
-> Ctrl+Z (Cut undo)
DeleteCommand undo — 원본 N개 cachedTransform.SetActive(true) + _partHidden 복원
`
변경 영향
- [완료] Cut+Paste = 사용자 의도 Move 패턴 완성
- [완료] Material 복사 정책 (QA-021) 자동 유지 (DuplicateCommand 재사용)
- [완료] 컴포넌트 (Sensors / Actuators / Pneumatic / Rotary / Vacuum / TowerLamp) 자동 복사
- [완료] 자식 hierarchy 자동 (UnityEngine.Object.Instantiate 재귀)
- [완료] Undo 통합 — Paste / Cut 모두 독립적 Ctrl+Z 가능
edit-copy-cut-paste 진행 누적
| 단계 | 버전 | 상태 |
|---|---|---|
| P1 (단축키 + Ribbon) | v0.1.285 | [완료] |
| P2 (씬 우클릭 메뉴) | v0.1.286 | [완료] |
| P3 (Cut Ctrl+X) | v0.1.289 | [완료] |
QA-073 인접 spec 100% 완료. 협업자 spec 진척 75% -> 100%.
다음 사이클 후보 (큐)
- studio-hamburger-lnb (사용자 명시 대기 — 사전 분석 완료)
- component-scene-inspector-ux (사용자 명시 대기)
- tower-lamp Material 풀링 (P3 잔존)
자가점검
- spec-vs-codebase-pre-check.md [완료] — DeleteCommand SetActive(false) + DuplicateCommand origGo.transform.parent 패턴 사전 검증
- silent-button-toast.md [완료] — edit-cut 정상 활성, listener 등록
- cycle-critic-review.md [완료] — 36라인 / 1000라인 한도 안전

v0.1.288 — v0.1.288 critic 회고 fix — 치명 2 + 중대 2 (44th seal 후보)

v0.1.288 v0.1.288 critic 회고 fix — 치명 2 + 중대 2 (44th seal 후보) zip release notes GitHub
사이클 요약
v0.1.284~287 누적 critic 회고 결과 CONDITIONAL -> 치명·중대 본 사이클 fix -> 44th stable seal 준비.
critic 결함 처리
| 등급 | 결함 | fix | 라인 |
|---|---|---|---|
| 치명 #1 | TowerLampEmissionDriver.cs:161 chCount<=0return -> 다중 부착 시나리오에서 다른 lamp skip | continue 로 변경 + 주석 | 1 |
| 치명 #2 | BuildObjectMenuItems "복사" 단일 분기가 CopySelected() SSOT 우회 | 우클릭 대상 선택 집합에 없으면 _selectedParts 임시 갱신 후 CopySelected() 호출 | +6 |
| 중대 #2 | edit-cut 버튼 SetEnabled(false) 만 — silent-button-toast.md 룰 위반 | clicked listener 추가 (안내 토스트) + tooltip 보강 | +5 |
| 중대 #3 | HdrIntensity 슬라이더 콜백에 clamp 부재 — 데이터 직접 입력 시 bloom overflow 가능 | Mathf.Clamp(v, 0.1f, 5.0f) 추가 | 1 |
deferred (사용자 합의 가능)
- 중대 #1: GetComponentsInChildren allocation 비용 — Material null 시점만 trigger. 현 디자인 의도 일치 (다수 lamp 시 풀링 P3 사이클)
- 중간 #1: blink anyBlink 매 100ms 재계산 — 캐시 패턴 도입 P3 사이클
- 중간 #2: chHeader Label lamp.LampCount vs Channels.Count 동기 — InitializeChannels 가 항상 동기 처리. 부분 삭제 경로 없음
- 사소 #1: _blinkOn lamp 단위 -> 채널별 독립 위상 P4 deferred
사이클 라인
| 파일 | 변경 |
|---|---|
| TowerLampEmissionDriver.cs | +1 (continue) |
| Factory00Bootstrap.cs | +12 (SSOT fix + cut listener + HDR clamp) |
총 ~13라인. 매우 작은 fix 사이클.
44th stable seal 후보
본 fix PASS 시 v0.1.273~v0.1.288 = 16 사이클 봉인:
- panel-resize P1+P2 (v0.1.273~278)
- tower-lamp P1+P2+P3 (v0.1.279~284, 287)
- critic fix (v0.1.283, 288)
- edit-copy-cut-paste P1+P2 (v0.1.285~286)
stable zip alias: factory00-windows-x64-v0.1.288-stable.zip 후보.

v0.1.287 — v0.1.287 tower-lamp P3 — HDR intensity 사용자 옵션화

v0.1.287 v0.1.287 tower-lamp P3 — HDR intensity 사용자 옵션화 zip release notes GitHub
사이클 요약
협업자 spec tower-lamp P3 polish 일부 — v0.1.282 P1 deferred 항목인 HDR intensity 사용자 옵션화. 기존 hardcode ×2.5 -> lamp.HdrIntensity 슬라이더 (0.5~5.0).
변경
| 영역 | 변경 | 라인 |
|---|---|---|
| TowerLampComponent | public float HdrIntensity = 2.5f 필드 추가 | +3 |
| TowerLampEmissionDriver.ApplyEmission | ch.Color * 2.5f -> ch.Color * Mathf.Max(0.1f, lamp.HdrIntensity) | 1 |
| RenderTowerLampCard | "발광(HDR)" 슬라이더 0.5~5.0 추가 (BlinkRateHz 옆) | +2 |
라인 합계: ~6. 매우 작은 사이클.
사용자 가치
| HDR | 시각 효과 |
|---|---|
| 0.5 | 약한 발광 (밝은 환경 / 실내 광원 강조) |
| 2.5 | 기본 (P1 기본값 - 표준 산업 환경) |
| 5.0 | 강한 발광 (어두운 환경 / 야외 / 비상 알림) |
Mathf.Max(0.1f, ...) 가드 — 0 또는 음수 입력 시 최소 0.1 (보이지 않는 부품 방지).
.twn 직렬화
[System.Serializable] 자동 처리 -> Save/Load 자동 통과. 기존 .twn 파일은 HdrIntensity 필드 누락 시 default 2.5 적용 (JsonUtility 기본 동작).
tower-lamp P3 deferred 잔존
- Material instance 풀링 — 현재 부품마다 새 instance. 다수 lamp 시 메모리 부담. 풀링은 별도 사이클
- 채널-Renderer 네이밍 컨벤션 옵션tower-lamp-ch0 등 이름 매칭 (현재 인덱스 기반)
- TowerLampEmissionDriver "Driver" 명명 충돌 rename — 다음 P4 정리 사이클
누적 진행 (협업자 spec)
| 단계 | 버전 | 상태 |
|---|---|---|
| tower-lamp P1 (데이터 + Inspector + Bridge + Emission) | v0.1.279~283 | [완료] |
| tower-lamp P2 (채널-Renderer 1:1) | v0.1.284 | [완료] |
| tower-lamp P3 (HDR intensity 옵션) | v0.1.287 | [완료] |
| tower-lamp P3 잔존 (풀링 / 명명) | — | [대기] |
| edit-copy-cut-paste P1+P2 | v0.1.285~286 | [완료] |
| edit-copy-cut-paste P3 (Cut snapshot) | — | [대기] |

v0.1.286 — v0.1.286 edit-copy-cut-paste P2 — 씬 우클릭 메뉴 Copy/Paste 추가

v0.1.286 v0.1.286 edit-copy-cut-paste P2 — 씬 우클릭 메뉴 Copy/Paste 추가 zip release notes GitHub
사이클 요약
협업자 spec edit-copy-cut-paste P2 의 우클릭 메뉴 통합. v0.1.285 의 단축키 + Ribbon 버튼에 이어 씬 우클릭 ContextMenu에 Copy/Paste 항목 추가. Cut 은 P3 deferred (snapshot semantics 별도 사이클).
변경
| 영역 | 변경 | 라인 |
|---|---|---|
| BuildObjectMenuItems | Copy / Paste 항목 2개 추가 (지우기 위에) | +20 |
라인 합계: ~20. 매우 작은 사이클 (1000라인 한도 충분).
메뉴 항목
`
씬 우클릭 (부품 위)
├── 보이기/감추기 (selCount 일괄)
├── 투명하게 보이기 / 투명 해제
├── ─── 구분 ───
├── 복사 [Ctrl+C] <- v0.1.286 신규
│ ├── selCount > 1 이고 우클릭 대상이 선택 집합에 포함 -> 선택 전체 복사
│ └── 그 외 -> 우클릭 단일 부품만 복사 (선택과 무관)
├── 붙여넣기 (N개) [Ctrl+V] <- v0.1.286 신규
│ └── 클립보드 비어있으면 "(클립보드 비어있음)" 라벨
├── ─── 구분 ───
├── 지우기
├── ─── 구분 ───
├── 새창에서 보기
└── 속성 (Property)
`
Cut deferred 사유 (P3)
Cut semantics 결정이 필요해 본 사이클에서 제외:
| 옵션 | trade-off |
|---|---|
| (A) Cut = Copy + Delete | DuplicateCommand 가 cachedTransform 필요 -> Delete 직후 Paste 시 fail |
| (B) Cut = Copy + 원본 inactive | DeleteCommand 의 SetActive(false) 패턴 활용. Paste 가능하나 Undo 복잡 |
| (C) Cut = Snapshot 보관 + 원본 삭제 | 가장 안전. 새 PasteSnapshotCommand IEditCommand 필요 (~100라인) |
P3 사이클에서 옵션 (C) 채택 가능성. 본 P2 = 우클릭 메뉴만.
누적 진행
| spec / 사이클 | 상태 |
|---|---|
| tower-lamp P1 + P2 | [완료] v0.1.279~284 |
| edit-copy-cut-paste P1 (단축키 + Ribbon) | [완료] v0.1.285 |
| edit-copy-cut-paste P2 (우클릭 메뉴) | [완료] v0.1.286 |
| edit-copy-cut-paste P3 (Cut snapshot semantics) | [대기] deferred |
| studio-hamburger-lnb | [대기] 사용자 명시 대기 |
| component-scene-inspector-ux | [대기] 사용자 명시 대기 |

v0.1.285 — v0.1.285 edit-copy-cut-paste P1 (Ctrl+C / Ctrl+V + Edit 탭 활성)

v0.1.285 v0.1.285 edit-copy-cut-paste P1 (Ctrl+C / Ctrl+V + Edit 탭 활성) zip release notes GitHub
사이클 요약
협업자 spec edit-copy-cut-paste P1 진입 (협업자 r073 10abd81 신규 승격). v0.1.268 에서 P2 미구현으로 비활성 처리됐던 Edit 탭 Cut/Copy/Paste 버튼 중 Copy / Paste 활성. Cut 은 P2 후속 사이클 분할 (사이클 크기 안전).
변경 요약
| 영역 | 변경 | 라인 |
|---|---|---|
| 단축키 (Update) | Ctrl+C / Ctrl+V 추가 (기존 Ctrl+D, Ctrl+A 옆) | +2 |
| 멤버 필드 | List _clipboard | +3 |
| 메서드 | CopySelected / PasteFromClipboard | +40 |
| Edit 탭 wiring | edit-copy / edit-paste clicked -> 핸들러 / edit-cut 만 비활성 유지 | +8 |
| ClearAllRuntimeComponents | _clipboard.Clear() 추가 (.twn 새 로드 시 reset) | +2 |
라인 합계: ~55. 본 사이클 = 작은 사이클 (1000라인 한도 안전 마진).
동작 흐름
`
[선택] -> [Ctrl+C 또는 Edit 탭 Copy] -> _clipboard 에 참조 보관
[Ctrl+V 또는 Edit 탭 Paste] -> 각 Part 마다 DuplicateCommand -> UndoStack push -> +50mm 오프셋
[Ctrl+Z] -> 모든 Paste 부품 Undo 가능 (DuplicateCommand IEditCommand 통합)
`
정책 결정
- 참조 보관 (vs 깊은 복사): clipboard 는 Part 참조만. Paste 시점에 DuplicateCommand 가 GameObject.Instantiate -> Material 복사 -> 컴포넌트 복제 (v0.1.243 QA-021 정책 그대로 활용)
- 원본 삭제 처리: clipboard 안 Part 가 삭제됐으면 cachedTransform == null 검출 -> skip + 토스트 안내
- 오프셋: DuplicateCommand 패턴 따라 origId 누적 카운터 사용 (반복 Paste 시 +50mm / +100mm / ...)
- Cut deferred: Cut = Copy + Delete 조합. 본 P1 에서는 Copy / Paste 만. Cut 은 P2 사이클 (DeleteCommand 와 PasteCommand 의 stack 통합 검증 필요)
- multi-select Paste: 선택 N개 -> Paste 시 N개 모두 복제 (DuplicateCommand 가 각각 처리)
P1 -> P2 deferred
- Cut (Ctrl+X) — Copy + Delete 조합. UndoStack 통합 (Cut + Paste 가 atomic 인지)
- 우클릭 메뉴 — Copy/Cut/Paste 항목 ContextMenu 추가 (spec 명시)
- clipboard 상태 UI — Edit 탭에 "Paste (n개)" 동적 라벨
- Material 복사 비용 옵션 — 현재 Paste 마다 Material.Instantiate. 다수 Paste 시 메모리 부담
누적 진행 (협업자 spec 큐)
| spec | 상태 |
|---|---|
| tower-lamp P1 + P2 | [완료] v0.1.279~284 |
| edit-copy-cut-paste P1 | [완료] v0.1.285 (Copy + Paste) |
| edit-copy-cut-paste P2 (Cut + 우클릭) | [대기] 다음 사이클 |
| studio-hamburger-lnb | [대기] 사용자 명시 대기 (큰 구조 변경) |
| component-scene-inspector-ux | [대기] 사용자 명시 대기 (큰 구조 변경) |
자가점검
- spec-vs-codebase-pre-check.md 룰 적용 — Bus property / _selectedParts / DuplicateCommand IEditCommand / 단축키 패턴 모두 사전 검증 PASS
- 변수 scope: _clipboard 클래스 필드 (메서드 로컬 X)
- API 일관성: DuplicateCommand 패턴 미러 -> 기존 Ctrl+D 와 동일 동작

v0.1.284 — v0.1.284 tower-lamp P2 채널-Renderer 1:1 매핑

v0.1.284 v0.1.284 tower-lamp P2 채널-Renderer 1:1 매핑 zip release notes GitHub
사이클 요약
협업자 spec QA-073 tower-lamp 신호 출력 명령의 P2 핵심 시각 효과 완성. P1 (v0.1.279~283) 에서는 모든 자식 Renderer 에 "가장 위 활성 채널" 단일 색만 적용 -> 멀티 채널 동시 발광 불가능. P2 에서 자식 Renderer 인덱스 기반 채널 1:1 매핑 -> R/Y/G 동시 점등 가능.
변경 요약
| 파일 | 변경 |
|---|---|
| TowerLampEmissionDriver.cs | Material[] -> Material[][] (per-channel) 캐시 / ApplyEmission 채널별 색 분배 / OnDestroy + InvalidateLamp 다차원 순회 |
라인 합계: ~210 -> ~230 (+20). 본 사이클 = ~50라인 / 1000라인 한도 안.
매핑 규칙
`
부품 자식 Renderer 순서 = 채널 인덱스
rends[0] ↔ Channel #1 (LampCount ≥ 1)
rends[1] ↔ Channel #2 (LampCount ≥ 2)
rends[2] ↔ Channel #3 (LampCount ≥ 3)
rends[3] ↔ Channel #4 (LampCount = 4)
`
- Renderer 부족 (rends.Length < LampCount): 가능한 채널까지만 매핑. 나머지는 빈 Material 배열 = silent skip
- Renderer 초과 (rends.Length > LampCount): 채널 안 닿는 Renderer 는 emission 미적용 (Lit 본래 색 유지)
- 사용자 관점: 부품 GLB/FBX 임포트 시 자식 메시 순서가 의미 가짐 — 위->아래 순서로 자식 추가 권장
동작 시나리오
| 시나리오 | 결과 (P1) | 결과 (P2) |
|---|---|---|
| Channel #1 (Red) ON | 모든 메시 빨강 | rends[0] 만 빨강 |
| Channel #1 (Red) + #2 (Yellow) ON | 모든 메시 빨강 (Red 우선) | rends[0] 빨강 + rends[1] 노랑 (동시) |
| Channel #1 Blink + #2 ON | Blink 채널만 토글 | rends[0] 빨강 토글 + rends[1] 노랑 (독립) |
P2 -> P3 deferred
- HDR intensity 사용자 옵션화 (현재 ×2.5 hardcode)
- 채널-Renderer 네이밍 컨벤션 옵션 (tower-lamp-ch0 등 이름 매칭)
- Material instance 풀링 (현재 부품마다 새 instance — 다수 lamp 시 메모리 사용량 증가)
- TowerLampEmissionDriver "Driver" 명명 충돌 rename
- TowerLampComponent.Id vs DriverInstanceId 이중 GUID 단일화
누적 진행 (협업자 spec QA-073)
| 단계 | 버전 | 상태 |
|---|---|---|
| 데이터 모델 | v0.1.279 | [완료] P1.1 |
| Inspector UI | v0.1.280 | [완료] P1.2 |
| Signal Sim | v0.1.281 | [완료] P1.3 |
| Bridge + Emission | v0.1.282 | [완료] P1.3 |
| critic fix | v0.1.283 | [완료] 43rd seal |
| 채널 1:1 매핑 | v0.1.284 | [완료] P2 핵심 완성 |
QA-073 = 사실상 완료. 잔존은 polish (P3).

v0.1.283 — v0.1.283 tower-lamp critic fix (치명 2 + 중대 3 + 중간 2)

v0.1.283 v0.1.283 tower-lamp critic fix (치명 2 + 중대 3 + 중간 2) zip release notes GitHub
사이클 요약
v0.1.282 critic CONDITIONAL -> 치명·중대 모두 본 사이클에서 fix -> PASS 전환. tower-lamp 4 사이클 (v0.1.279~v0.1.283) 43rd stable seal 후보.
critic 결함 처리표
| 등급 | 결함 | 파일 | fix |
|---|---|---|---|
| 치명 #1 | Material cache stale -> MissingReferenceException | TowerLampEmissionDriver.cs:114-133 | cache valid check (m == null) + stale 시 Destroy + 재생성 |
| 치명 #2 | r.materials 반복 호출 + OnDestroy 누락 -> Material instance 누수 | 동상 L125-129 | 한 번만 fetch + OnDestroy_matCache 전 Destroy |
| 중대 #1 | LampCount 변경 시 _blinkOn stale | Factory00Bootstrap.cs:5833 LampCount 슬라이더 | InvalidateLamp(DriverInstanceId) 호출 추가 (cache + blink phase 정리) |
| 중대 #2 | Bridge ch.IsOn vs Sim 토글 SSOT 충돌 | Factory00Bootstrap.cs:5912-5928 | Sim 토글 SetEnabled(ModbusCoilBase <= 0) + tooltip 명시 |
| 중대 #3 | URP _EMISSION 키워드 불충분 -> 렌더 반영 안 됨 | TowerLampEmissionDriver.cs:128 | globalIlluminationFlags = RealtimeEmissive 추가 |
| 중간 #1 | Update 매 프레임 Parts 순회 -> GC 압력 | TowerLampEmissionDriver.cs Update() | 100ms throttle (k_UpdateInterval = 0.1f) — blink 정확도 OK |
| 중간 #3 | "채널 4" 라벨 의미 불명확 | Factory00Bootstrap.cs:5852 | "채널 (LampCount색등)" |
신규 공개 API
TowerLampEmissionDriver.InvalidateLamp(string driverInstanceId) — lamp 제거 / 재구성 시 Material instance Destroy + cache + blink phase 정리. RemoveTowerLampFromPart + LampCount 슬라이더 양쪽에서 호출.
사용자 UX 변경 (중대 #2)
- Modbus 연결 (CoilBase>0): Sim 토글 회색 비활성. tooltip = "Modbus 코일 N+i 가 SSOT — Sim 무력. Coil Base = 0 으로 설정하면 활성"
- Modbus 미연결 (CoilBase=0): Sim 토글 정상 동작 (시연 모드)
비코딩 사용자가 "누르는데 안 켜진다" 혼란 해소.
deferred -> 후속 사이클
| 등급 | 결함 | 처리 시점 |
|---|---|---|
| 중간 #2 | ModbusCoilBase sentinel <= 0 vs == 0 의도 명시 | v0.1.284 코멘트 |
| 사소 #1 | TowerLampEmissionDriver "Driver" 명명 충돌 | rename은 다음 P2 사이클 |
| 사소 #2 | TowerLampComponent.Id vs DriverInstanceId 이중 GUID | 사용처 정리 후 단일화 |
사이클 종료 라인 합계
| 파일 | 변경량 |
|---|---|
| TowerLampEmissionDriver.cs | ~95 -> ~210 (+115, 치명 2 + 중대 3 + 중간 1 fix) |
| Factory00Bootstrap.cs | +12 (LampCount + Remove + Sim 토글 + chHeader) |
본 사이클 = ~127라인 / 1000라인 한도 안.

v0.1.282 — v0.1.282 tower-lamp Bridge + Emission Driver (QA-073 P1.3)

v0.1.282 v0.1.282 tower-lamp Bridge + Emission Driver (QA-073 P1.3) zip release notes GitHub
사이클 요약
협업자 spec QA-073 tower-lamp 신호 출력 명령의 P1.3 마무리. v0.1.281 에서 Inspector + Signal Sim 수동 토글까지 완료했고, 본 사이클은 실 PLC 코일 ↔ Emission 시각 효과 양방향 자동 동기를 추가한다.
추가 컴포넌트
| 파일 | 역할 | 라인 수 |
|---|---|---|
| Assets/Scripts/Outputs/TowerLampPlcBridge.cs | MonoBehaviour. ModbusTcpAdapter 코일 폴링 + edge detect -> TowerLampStateChangedEvent publish | ~65 |
| Assets/Scripts/Outputs/TowerLampEmissionDriver.cs | MonoBehaviour. EventBus 구독 + Renderer Material instance + URP _EmissionColor HDR + Blink schedule | ~150 |
| Factory00Bootstrap.cs SetupScene | 2 컴포넌트 등록 (Modbus 활성 시 Bridge, 항상 Emission) | +12 |
동작 흐름
`
[Modbus 코일 N+i] - 폴링(Update) ────┐
├─-> TowerLampStateChangedEvent ─-> EmissionDriver
[Inspector Sim 토글] - Publish ──────┘ │
Material._EmissionColor (HDR)
Blink 채널: BlinkRateHz 반주기 토글
`
- Modbus 미연결 환경: Sim 토글만으로도 Emission 동작 (Driver 는 Modbus 무관)
- Modbus 연결 + CoilBase>0: PLC 변경 시 IsOn 자동 갱신 + Emission 즉시 반영
- Blink 채널: IsOn AND IsBlink 인 채널은 BlinkRateHz 주기로 on/off 토글
P1 -> P2 deferred
- 채널별 Renderer 매핑: 현재 P1 = 부품 안 모든 Renderer 에 "가장 위 활성 채널" 단일 색 적용. P2 차후 사이클에서 채널 ↔ 메시 1:1 매핑 (네이밍 컨벤션 또는 부품 child index 기반)
- HDR intensity 사용자 조정: 현재 ×2.5 hardcode. 사용자 옵션화는 P2
- .twn 직렬화: TowerLampComponent [System.Serializable] 자동 처리 -> Save/Load 자동 통과 (별도 코드 0)
누적 (v0.1.279~282)
| 버전 | 단계 | 변경 |
|---|---|---|
| v0.1.279 | P1.1 데이터 모델 | TowerLampComponent / Channel / Event / Part.TowerLamps / Add 명령 |
| v0.1.280 | P1.2 Inspector UI | RenderTowerLampBlock + RenderTowerLampCard + 색상 7-preset + Blink Toggle |
| v0.1.281 | P1.3 Signal Sim | Sim 토글 + ModbusCoilBase 필드 + 채널 opacity 시각화 |
| v0.1.282 | P1.3 Bridge + Emission | TowerLampPlcBridge + TowerLampEmissionDriver + Bootstrap 등록 |
다음 사이클: v0.1.283 critic + 43rd stable seal.

v0.1.281 — v0.1.281 — tower-lamp Signal Sim 수동 + Coil Base 매핑 + IsOn 시각화

v0.1.281 v0.1.281 — tower-lamp Signal Sim 수동 + Coil Base 매핑 + IsOn 시각화 zip release notes GitHub
tower-lamp 사이클 진행
| 사이클 | 범위 | 상태 |
|---|---|---|
| v0.1.279 | 데이터 모델 + Add 명령 | [완료] |
| v0.1.280 | Inspector UI | [완료] |
| v0.1.281 (이번) | Signal Sim 수동 + CoilBase + IsOn 시각 | 진행 |
| v0.1.282 | Modbus Bridge + Emission (실 3D 발광) | 예정 |
| v0.1.283 | .twn 직렬화 + critic + seal | 예정 |
이번 사이클 변경 (scope 축소)
협업자 spec brief 원문 부재 + cycle-critic-review.md 1000라인 한도 + Bridge / Emission 묶음 진행 시 600라인+ 예상 -> 본 사이클은 Signal Sim 수동 + 코일 매핑 데이터 + Inspector IsOn 시각화 만 처리. 실 Modbus 폴링 Bridge + URP _EmissionColor HDR 효과는 v0.1.282 분리.
1. TowerLampComponent.ModbusCoilBase 필드 신규
`csharp
// 채널 i 의 코일 = CoilBase + i. 0 = 미연결.
public int ModbusCoilBase = 0;
`
Modbus TCP/Serial 어느 쪽이든 COIL:{base+i} 주소로 매핑. v0.1.282 Bridge가 이 값을 폴링.
2. Inspector 채널 row Sim 토글
`
[#1] [■ 색박스 (IsOn opacity 1.0 / OFF 0.30)] [▼ Red] [[ ] Blink] [[ ] Sim]
`
Sim 토글 변경 시:
1. ch.IsOn = !ch.IsOn
2. 색박스 opacity 즉시 갱신
3. EventBus.Publish(TowerLampStateChangedEvent) 발행 — v0.1.282 Emission Driver 가 구독
Modbus 미연결 환경(데모 PC)에서도 시연 가능.
3. Inspector Coil Base 필드
채널 row 아래 Coil Base 정수 입력. 0~9999 clamp. 0 = 미연결.
4. 색박스 opacity = IsOn 시각화
초기 렌더 시 ch.IsOn에 따라 색박스가 진하게(1.0) / 어둡게(0.30) 표시. PLC 신호 또는 Sim 토글 변경 즉시 반영.
4대 불변 원칙 검토
| 원칙 | 판정 |
|---|---|
| ① 임포트 전용 | [완료] UI/데이터만 |
| ② 경량 물리 | [완료] 물리 0 |
| ③ 비코딩 UX | [완료] Inspector 토글/필드만 |
| ④ 이벤트 기반 | [완료] TowerLampStateChangedEvent 발행 (v0.1.282 구독자 추가) |
변경 파일
- Assets/Scripts/Outputs/TowerLampComponent.csModbusCoilBase 필드 추가
- Assets/Scripts/Game/Factory00Bootstrap.csRenderTowerLampCard Sim 토글 + Coil Base 필드 + IsOn opacity (~30라인 추가)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.280 -> 0.1.281
검증 절차
1. Add Tower Lamp -> 색박스 4개 모두 어둡게(opacity 0.30) 표시
2. 채널 #1 Sim 토글 ON -> 색박스 즉시 진해짐(opacity 1.0)
3. Coil Base 100 입력 -> 다음 사이클 Bridge 폴링 시 COIL:100~103 매핑 준비
4. EventBus 구독자가 향후 추가되면 자동 발광 효과 트리거
다음 사이클
- v0.1.282 — TowerLampPlcBridge (MonoBehaviour, Modbus 폴링 + edge detect) + TowerLampEmissionDriver (URP _EmissionColor HDR + Blink Update) + .twn 직렬화 통합
- v0.1.283 — critic + 43rd stable seal (v0.1.273~283 누적)

v0.1.280 — v0.1.280 — tower-lamp P1.2 Inspector UI (색등 수 + 채널별 색상/Blink)

v0.1.280 v0.1.280 — tower-lamp P1.2 Inspector UI (색등 수 + 채널별 색상/Blink) zip release notes GitHub
tower-lamp 3 사이클 분할 중 2번째
| 사이클 | 범위 | 상태 |
|---|---|---|
| v0.1.279 | 데이터 모델 + Add 명령 | [완료] |
| v0.1.280 (이번) | Inspector UI | 진행 |
| v0.1.281 | Modbus 구독 + Emission + Signal Sim 수동 | 예정 |
이번 사이클 변경
Inspector "출력부: 타워램프" 블록 신규
선택 부품에 TowerLamps 가 있으면 Inspector 하단에 새 섹션 출현. 첫 부착 시 "+ 타워램프" 버튼만 노출.
부착 후 카드 구성:
- 헤더TL-{8자리} [N색등] + 삭제 버튼
- 색등 수 슬라이더 — 1 ~ 4 정수. 변경 시 InitializeChannels(N) 호출로 채널 리스트 재생성. Inspector 즉시 재렌더
- 점멸(Hz) 슬라이더 — 0.5 ~ 5.0
- 채널 row 반복 (LampCount 개)
- #N 위치 라벨 (24px)
- 현재 색상 박스 (22×14, border)
- 색상 프리셋 dropdown 7종 (Red / Yellow / Green / Blue / White / Cyan / Magenta)
- Blink 토글
색상 프리셋 helper (정적)
ColorFromPresetName(string) / NearestColorPresetIndex(Color) — RGB 거리 최소값으로 dropdown 초기값 매칭. spec QA-018 답변 (B안 URP _EmissionColor HDR) 대비 채널 색상 SSOT.
Add/Remove helper
- AddTowerLampToPart(Part) — 부품당 1개 강제, 토스트 안내
- RemoveTowerLampFromPart(Part, TowerLampComponent) — 토스트 + Inspector 재렌더
4대 불변 원칙 검토 (spec §2)
| 원칙 | 판정 |
|---|---|
| ① 임포트 전용 | [완료] UI 조작만 |
| ② 경량 물리 | [완료] 데이터/UI만, 물리 0 |
| ③ 비코딩 UX | [완료] Inspector 슬라이더 + dropdown + 토글만 |
| ④ 이벤트 기반 | 예정 — TowerLampStateChangedEvent 구독은 v0.1.281 Bridge에서 |
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs — RenderTowerLampBlock + RenderTowerLampCard + ColorFromPresetName + NearestColorPresetIndex + AddTowerLampToPart + RemoveTowerLampFromPart (~220라인 추가)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.279 -> 0.1.280
검증 절차
1. Add Tower Lamp -> Inspector 하단 "출력부: 타워램프" 섹션 확인
2. 색등 수 슬라이더 4 -> 2 변경 -> 채널 row 2개로 재구성 확인
3. 채널 #1 색상 dropdown -> Yellow 선택 -> 색상 박스 즉시 갱신
4. Blink 토글 ON -> 데이터 반영 (Modbus 효과는 v0.1.281에서)
5. 삭제 버튼 -> "+ 타워램프" 버튼 복귀
다음 사이클
- v0.1.281 — Modbus 구독 Bridge + Emission 효과 (URP _EmissionColor HDR) + Signal Sim 수동 제어
- v0.1.282 — .twn 직렬화 통합 + critic 검토
- 43rd stable seal — v0.1.273~282 누적 후 봉인

v0.1.279 — v0.1.279 — tower-lamp P1.1 데이터 모델 + Add Tower Lamp 명령

v0.1.279 v0.1.279 — tower-lamp P1.1 데이터 모델 + Add Tower Lamp 명령 zip release notes GitHub
협업자 spec tower-lamp P1 진입 (QA-073 명시 착수 요청)
협업자 PM께서 가장 명시적으로 착수 요청해 주신 spec입니다(QA-073). 4종세트 완비 + 출력부 카테고리 정식 승격 상태이며, 전체 ~400라인을 cycle-critic-review.md 룰 한도 준수를 위해 3 사이클로 분할 진입합니다.
| 사이클 | 범위 | 라인 |
|---|---|---|
| v0.1.279 (이번) | 데이터 모델 + Add 명령 | ~150 |
| v0.1.280 | Inspector UI (LampCount + 채널별 색상/Blink) | ~150 |
| v0.1.281 | Modbus 구독 Bridge + Emission 효과 + Signal Sim 수동 | ~100 |
이번 사이클 (v0.1.279) 변경
1. 데이터 모델 신규
Assets/Scripts/Outputs/TowerLampComponent.cs (신규)
`csharp
namespace Factory00.Outputs
{
[System.Serializable]
public class TowerLampChannel
{
public int Position = 0;
public Color Color = Color.red;
public bool IsBlink = false;
[System.NonSerialized] public bool IsOn = false; // 런타임
}
[System.Serializable]
public class TowerLampComponent
{
public string Id = System.Guid.NewGuid().ToString();
public int LampCount = 4; // 1~4
public List Channels = new();
public float BlinkRateHz = 1.0f;
public string DriverInstanceId = System.Guid.NewGuid().ToString();
// 기본 4채널 R/Y/G/B 자동 초기화
}
}
`
2. 이벤트 신규
Assets/Scripts/Events/TowerLampEvents.cs (신규) — TowerLampStateChangedEvent readonly struct
Assets/Scripts/Events/EventBus.csOnTowerLampStateChanged event + Publish(TowerLampStateChangedEvent) overload
3. Part.TowerLamps 리스트
Assets/Scripts/Core/Part.csList TowerLamps 필드 추가. 다른 컴포넌트 리스트(Sensors / Actuators / VacuumEjectors 등)와 동일 패턴.
4. Ribbon Model 탭 Add Tower Lamp 명령
`xml
tooltip="선택 부품 각각에 TowerLamp 1개 부착 (4채널 R/Y/G/B, Modbus 신호 연동)"/>
`
선택 부품에 TowerLampComponent 1개 부착(이미 있으면 skip). 다중 선택 시 부착/skip 카운트 토스트.
4대 불변 원칙 검토 (spec §2)
| 원칙 | 판정 |
|---|---|
| ① 임포트 전용 | [완료] UI 조작만, 모델링 없음 |
| ② 경량 물리 | [완료] 물리 없음, Emission 재질 효과만 |
| ③ 비코딩 UX | [완료] Inspector + 우클릭 메뉴로만 조작 (v0.1.280에서 Inspector UI 추가) |
| ④ 이벤트 기반 | [완료] TowerLampStateChangedEvent + ModbusSignalChangedEvent 구독 (v0.1.281에서 구독자 추가) |
---
변경 파일
- Assets/Scripts/Outputs/TowerLampComponent.cs (신규) — TowerLampChannel + TowerLampComponent
- Assets/Scripts/Events/TowerLampEvents.cs (신규) — TowerLampStateChangedEvent
- Assets/Scripts/Events/EventBus.cs — Publish overload + event
- Assets/Scripts/Core/Part.cs — TowerLamps 리스트 필드 추가
- Assets/UI/Components/Ribbon.uxml — model-add-tower-lamp 버튼
- Assets/Scripts/Game/Factory00Bootstrap.cs — Add Tower Lamp 핸들러 (~25라인)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.278 -> 0.1.279
---
검증 절차
1. Model 탭 -> Add Tower Lamp 버튼 표시 확인
2. 선택 부품 1개 + 클릭 -> "Tower Lamp 1개 부착 (4채널 R/Y/G/B · Inspector는 다음 사이클)" 토스트
3. 같은 부품에 재클릭 -> "이미 부착" skip
4. 다중 선택 + 클릭 -> 부착/skip 카운트 토스트
5. Inspector UI는 v0.1.280에서 추가 예정 (현재는 데이터만 부착)
---
다음 사이클 예정
- v0.1.280 — TowerLamp Inspector UI (LampCount 슬라이더 + 채널별 색상 드롭다운 + Blink 토글 + BlinkRateHz 슬라이더)
- v0.1.281 — Modbus 구독 Bridge + Emission 효과 (URP _EMISSION keyword + _EmissionColor HDR) + Signal Sim 수동 제어
- v0.1.282 — .twn 직렬화 통합 (TowerLamps 리스트 저장/복원) + critic 검토
- 43rd stable seal — v0.1.273~282 누적 후 봉인 예정

v0.1.278 — v0.1.278 — Panel Resize P2-B 압정 모드 [고정]/[위치] + 오토하이드 1000ms

v0.1.278 v0.1.278 — Panel Resize P2-B 압정 모드 [고정]/[위치] + 오토하이드 1000ms zip release notes GitHub
studio-panel-resize-pin P2 완결 (v0.1.277 + v0.1.278)
협업자 spec의 P2 범위 두 번째 절반입니다. 압정(Pin) 모드 토글과 1000ms 오토하이드 동작을 구현했습니다.
변경 동작
1. 압정 버튼 (parts-section 헤더, 접기 버튼 옆)
- [고정] 고정 모드 (기본값, Q-3 확정): 마우스가 좌측 패널을 떠나도 패널이 유지됩니다.
- [위치] 오토하이드 모드: 마우스가 좌측 패널을 떠나고 1000ms (Q-2 확정) 후 자동으로 접힘 -> 슬라이드 아웃 효과.
압정 클릭 시 두 모드를 토글하며 PlayerPrefs factory00.sidebar_pinned에 영구 저장됩니다. 앱 재실행 시 직전 모드 그대로 복원됩니다.
2. 미니 리본 ▶ hover -> 즉시 슬라이드 인
오토하이드 모드([위치])에서 패널이 접힘 상태일 때, 사용자가 씬 좌측 미니 리본 ▶에 마우스를 hover하면 즉시 _leftPanelVM.ToggleCollapse() 호출로 패널이 다시 펼쳐집니다. 클릭하지 않아도 마우스 진입만으로 자동 슬라이드 인 효과.
3. SidebarPinChangedEvent 발행
`csharp
public readonly struct SidebarPinChangedEvent
{
public readonly bool IsPinned;
public readonly double Timestamp;
}
`
압정 토글 시 Bus.Publish(new SidebarPinChangedEvent(...)) 호출. 향후 다른 UI 영역에서 압정 상태 변경을 구독할 수 있습니다.
4. IVisualElementScheduledItem 타이머 패턴
UI Toolkit의 element.schedule.Execute(...).StartingIn(1000) 패턴으로 1000ms 지연 타이머를 구현했습니다. MouseEnterEvent 발생 시 hideTimer?.Pause()로 즉시 취소 — 마우스가 재진입하면 hide가 일어나지 않습니다.
---
변경 파일
- Assets/UI/MainHUD.uxmlsidebar-pin-btn 추가 (접기 버튼 좌측, 압정 토글)
- Assets/Scripts/Events/SidebarEvents.cs (신규) — SidebarPinChangedEvent readonly struct
- Assets/Scripts/Events/EventBus.csOnSidebarPinChanged event + Publish overload
- Assets/Scripts/Game/Factory00Bootstrap.cs — 압정 wiring + MouseLeave/Enter 타이머 + 미니 리본 hover slide-in (~50라인)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.277 -> 0.1.278
---
검증 절차
1. 기본 고정 모드: 앱 시작 시 압정 [고정] 표시. 마우스가 좌측 패널 떠나도 유지.
2. 압정 클릭 -> [위치] 변경 + 토스트 "오토하이드 ([위치] 마우스 이탈 1초)"
3. 오토하이드 모드 + 마우스 이탈: 1초 대기 후 좌측 패널 자동 접힘 + 씬 좌측 ▶ 미니 리본 표시
4. ▶ 미니 리본 hover -> 즉시 패널 펼침 (클릭 없이)
5. 압정 다시 클릭 -> [고정] 복귀 + 토스트 "고정 ([고정])"
6. 앱 재실행 -> 직전 모드 그대로 복원 (PlayerPrefs 영구)
---
studio-panel-resize-pin spec 완료 — P1 + P2
| 사이클 | 범위 | 완료 |
|---|---|---|
| v0.1.276 | P1 hover accent + PanelResizedEvent | [완료] |
| v0.1.277 | P2-A 접기 버튼 우측 상단 + 미니 리본 ▶ | [완료] |
| v0.1.278 | P2-B 압정 + 오토하이드 + SidebarPinChangedEvent | [완료] |
spec의 P3 (패널 도킹)는 Unity UI Toolkit 도킹 PoC 통과 후 별도 진입 (기술 게이트 미통과 상태).
---
다음 사이클 예정
- v0.1.279~ — tower-lamp P1 (협업자 QA-073 직접 착수 요청, ~400라인 큰 사이클) 또는 다음 P1 spec
- 43rd stable seal — v0.1.273~282 8~10 사이클 누적 후 봉인 예정

v0.1.277 — v0.1.277 — Panel Resize P2-A 접기 버튼 우측 상단 + 미니 리본 (≡와 병행)

v0.1.277 v0.1.277 — Panel Resize P2-A 접기 버튼 우측 상단 + 미니 리본 (≡와 병행) zip release notes GitHub
협업자 spec studio-panel-resize-pin P2 절반 진입 (사용자 명시 "자율진행")
협업자 PM께서 정식 승격해 주신 5건 spec 중 가장 작은 사이클부터 진입했습니다. spec의 P2 범위를 절반으로 분할하여 v0.1.277(접기 버튼 + 미니 리본)과 v0.1.278(압정 + 오토하이드 + 이벤트)로 처리합니다.
변경 동작
1. 좌측 패널 우측 상단 <- 접기 버튼
부품 섹션 헤더 "부품" 라벨 우측에 <- 접기 버튼이 추가됩니다. 기존 Ribbon 좌측 햄버거 ≡ 버튼은 그대로 유지되며 동일한 _leftPanelVM.ToggleCollapse() 호출입니다.
`xml
tooltip="좌측 패널 접기 (F11)"
style="font-size:11px; padding:2px 8px; min-width:24px;"/>
`
2. 씬 좌측 floating 미니 리본 ▶
좌측 패널이 접힌 상태일 때 씬 뷰포트 좌측 가장자리에 세로 미니 리본 버튼 이 표시됩니다.
`xml
style="position:absolute; left:0; top:120px; width:18px; height:80px;
background-color:rgba(255,217,115,0.18); color:rgb(255,217,115);
border-radius:0 4px 4px 0; display:none;"/>
`
- 펼침 상태: display:none
- 접힘 상태: display:flex (자동 표시)
- 클릭 -> _leftPanelVM.ToggleCollapse() -> 패널 복원
3. 기존 ≡ 햄버거 + F11 단축키 그대로
세 가지 UI(우측 상단 <- / 씬 좌측 ▶ / Ribbon 좌측 ≡)와 F11 키 모두 같은 SSOT _leftPanelVM.ToggleCollapse()를 호출합니다. 사용자가 어느 경로로도 토글 가능합니다.
---
sidebar-mini-rail visibility 동기화
_leftPanelVM.OnCollapsedChanged 콜백에 미니 리본 visibility 라인을 추가했습니다.
`csharp
if (sidebarMiniRail != null)
sidebarMiniRail.style.display = collapsed ? DisplayStyle.Flex : DisplayStyle.None;
`
초기 상태 sync도 동일하게 처리하여, 앱 재시작 시 직전 collapsed 상태가 PlayerPrefs로 복원되어도 미니 리본이 일관 표시됩니다.
---
변경 파일
- Assets/UI/MainHUD.uxmlsidebar-collapse-btn (parts-section 헤더 우측) + sidebar-mini-rail (씬 좌측 floating) 추가
- Assets/Scripts/Game/Factory00Bootstrap.cssidebar-collapse-btn / sidebar-mini-rail wiring + collapsed 콜백에 미니 리본 visibility 동기화 (~15라인)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.276 -> 0.1.277
---
검증 절차
1. 좌측 패널 펼친 상태: 부품 헤더 우측에 <- 버튼이 보이는지 확인
2. <- 클릭 -> 좌측 패널 접힘 + 씬 좌측 가장자리에 노란 미니 리본 표시
3. 미니 리본 클릭 -> 좌측 패널 복원
4. 기존 Ribbon 햄버거 + F11 단축키 모두 같은 토글 동작 (회귀 없음)
---
다음 사이클 예정
- v0.1.278 — Panel Resize P2-B (압정 모드 [고정]/[위치] + 오토하이드 1000ms + SidebarPinChangedEvent + PlayerPrefs factory00.sidebar_pinned)
- v0.1.279~ — 다음 P1 spec 진입 (사용자 우선순위 명시 시: tower-lamp / LNB / component-scene-UX / edit-cut-copy-paste 중)
- 43rd stable seal — v0.1.273~280 누적 후 봉인 예정

v0.1.276 — v0.1.276 — Panel Resize P1 (hover accent 색상 + PanelResizedEvent + 드래그 강조)

v0.1.276 v0.1.276 — Panel Resize P1 (hover accent 색상 + PanelResizedEvent + 드래그 강조) zip release notes GitHub
협업자 신규 spec P1 진입 — studio-panel-resize-pin
협업자 PM께서 2026-05-21에 구상중 -> 스튜디오 카테고리로 정식 승격한 두 신규 spec 중 첫 번째 P1 사이클입니다. 사용자 명시 "계속진행"으로 P1 진입 trigger를 받았습니다.
스펙(studio-panel-resize-pin-summary.md r001)의 P1 범위는 "패널 상하 리사이즈 + 리사이즈 바 hover 인디케이터 + PanelResizedEvent 발행"입니다. 다행히 기존 codebase에 상하 리사이즈 드래그 로직 + 커서 변경은 v0.1.101~167 사이클에서 이미 구현되어 있었습니다. 이번 P1 사이클은 spec이 요구한 hover accent 색상 + 드래그 중 더 진한 색상 + 이벤트 발행 부분만 추가하는 형태입니다.
---
spec ↔ codebase 사전 검토 (룰 spec-vs-codebase-pre-check.md)
| spec 가정 | codebase 실제 | 처리 |
|---|---|---|
| EventBase UnityEvent 패턴 | readonly struct *Event + Bus.Publish SSOT | adapter — PanelResizedEvent readonly struct 신규 |
| PanelResizedEvent { PanelId, NewHeightPx } | 동일 구조 가능 | PASS — Assets/Scripts/Events/PanelEvents.cs 신규 |
| PlayerPrefs panel_{id}_height | 기존 factory00.parts_section_height / factory00.inspector_section_height SSOT | 기존 key 그대로 재사용 |
| parts-inspector-resize / inspector-motor-resize element | UXML 이미 존재 (MainHUD.uxml:43, 52) + 드래그 wiring (Bootstrap.cs:1089~1281) | hover 색상 + 이벤트만 추가 |
| 리사이즈 바 hover 커서 (resize-ns) | 이미 SetBuiltinCursor(handle, 2) 적용 (v0.1.167) | PASS — 별도 변경 X |
판정: PASS — adapter layer + 작은 추가 변경 (~50라인). cycle-critic-review.md 룰의 핫픽스 한도 내.
---
추가 동작
1. `PanelResizedEvent` 신규
`csharp
public readonly struct PanelResizedEvent
{
public readonly string PanelId;
public readonly float NewHeightPx;
public readonly double Timestamp;
}
`
parts-section / inspector-section 두 패널 리사이즈 종료 시 Bus.Publish(new PanelResizedEvent(...)) 호출.
2. Hover 시 accent 색상 (RGB 255,217,115 골드)
- idle: rgba(255,255,255,0.08) (회색)
- hover: rgba(255,217,115,0.30) (accent 옅게)
- 드래그 중: rgba(255,217,115,0.55) (accent 진하게)
- 드래그 종료: idle 색상 복귀
기존 inline style 패턴(v0.1.166)을 그대로 유지하며 MouseEnterEvent / MouseLeaveEvent / PointerDownEvent 콜백으로 색상 변경합니다.
3. 두 splitter 모두 일관 적용
- parts-inspector-resize (부품 ↔ 프로퍼티 경계)
- inspector-motor-resize (프로퍼티 ↔ 모터 경계)
좌측 패널 좌우 폭 splitter(left-panel-resize)는 이번 spec 범위 외 (P2~P3 작업).
---
변경 파일
- Assets/Scripts/Events/PanelEvents.cs (신규) — PanelResizedEvent readonly struct
- Assets/Scripts/Game/Factory00Bootstrap.cspartsResize + inspMotorResize 두 곳에 hover/드래그 색상 + Bus.Publish 추가 (~50라인)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.274 -> 0.1.276 (v0.1.275는 docs-only로 build skip)
---
검증 절차
1. 부품 ↔ 프로퍼티 경계선 마우스 hover -> accent 골드 옅은 색 표시 확인
2. 드래그 시작 -> 더 진한 골드 색 변경 확인
3. 드래그 종료 -> idle 회색 복귀 + "부품 영역: NNNpx" 토스트
4. 프로퍼티 ↔ 모터 경계선도 동일 동작 확인
5. PlayerPrefs factory00.parts_section_height / factory00.inspector_section_height 갱신 + 앱 재실행 시 복원
---
다음 사이클 예정
- v0.1.277 — Panel Resize P2 (접기 버튼 우측 상단 이동 + 압정/오토하이드 1000ms) — SidebarPinChangedEvent + PlayerPrefs sidebar_pinned
- v0.1.278~ — studio-hamburger-lnb P1 (Ribbon File 탭 -> LNB 사이드 패널, 큰 구조 변경 — 사용자 명시 후)
- 43rd stable seal — v0.1.273~278 누적 후 봉인 예정

v0.1.274 — v0.1.274 — Collision 결과 윈도우 backdrop click 닫기 (일관성 polish)

v0.1.274 v0.1.274 — Collision 결과 윈도우 backdrop click 닫기 (일관성 polish) zip release notes GitHub
v0.1.272 QA-069 fix 일관성 보강
v0.1.272에서 추가한 Collision Check 결과 윈도우(OpenCollisionResultsSubWindow)에 backdrop click -> 닫기 동작이 누락되어 있었습니다. 같은 모달 패턴을 사용하는 OpenPartInSubWindow (v0.1.030 "새창에서 보기")에는 이미 동일 동작이 있어 사용자 입장에서는 일관성이 깨진 상태였습니다.
기존 닫기 경로는 X 버튼과 ESC 키 두 가지뿐이라 마우스로 다이얼로그 바깥의 어두운 배경을 클릭해도 닫히지 않아 약간의 답답함이 있었습니다. 이번 사이클에서 5라인 추가로 해결했습니다.
`csharp
// v0.1.274 — backdrop click close (OpenPartInSubWindow와 일관성)
_subWindowOverlay.RegisterCallback(evt =>
{
if (evt.target == _subWindowOverlay) CloseSubWindow();
});
`
다이얼로그 본문(dialog) 영역의 클릭은 evt.target != _subWindowOverlay이므로 닫히지 않고, 배경(_subWindowOverlay) 직접 클릭만 모달을 닫습니다. 항목 클릭 동작과 충돌 없이 동작합니다.
---
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.csOpenCollisionResultsSubWindow 끝에 backdrop click 콜백 5라인 추가
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.273 -> 0.1.274
---
검증 절차
1. Collision Check 클릭 -> 결과 윈도우 표시
2. 어두운 배경(다이얼로그 바깥) 클릭 -> 모달 닫힘 확인
3. 다이얼로그 본문 또는 항목 행 클릭 -> 닫히지 않고 정상 동작 (항목 클릭은 카메라 포커스)
4. X 버튼 / ESC 키 닫기 -> 기존처럼 정상
---
다음 사이클 예정
- v0.1.275~ — QA-014 PM 회신 받으면 root cause fix / QA-065 P2 검토 답변 / 잔존 협업자 spec
- 43rd stable seal — v0.1.273~278 5~6 사이클 누적 후 봉인 예정 (post-42nd polish 시리즈)

v0.1.273 — v0.1.273 — Camera.main 헬퍼 + publish marker 3종 hook + 룰 fix (42nd seal post-polish)

v0.1.273 v0.1.273 — Camera.main 헬퍼 + publish marker 3종 hook + 룰 fix (42nd seal post-polish) zip release notes GitHub
42nd seal post-polish — 3건 일괄 처리
42nd stable seal(v0.1.272) 봉인 직후의 작은 정리 사이클입니다. critic deferred 처리, 핸드오프 자동화 완성, 회고 룰 fix 세 가지를 묶어서 진행했습니다.
---
1. Camera.main 즉석 조회 헬퍼 추출 (42nd seal 중간 deferred 종료)
42nd seal 봉인 시 critic이 "Camera.main?.GetComponent() 즉석 조회가 두 곳에서 중복되어 있어 헬퍼 추출이 권장된다"고 중간 결함으로 지적했습니다. 이번 사이클에서 헬퍼 메서드를 추가하고 두 호출처를 모두 교체했습니다.
`csharp
// v0.1.273 — CameraViewController 즉석 조회 헬퍼 (42nd seal 중간 결함 deferred 종료).
Factory00.Game.CameraViewController GetCameraViewController()
{
var cam = Camera.main;
return cam != null ? cam.GetComponent() : null;
}
`
- Bootstrap.cs:3045 (더블클릭 카메라 포커스) — GetCameraViewController() 호출로 교체
- Bootstrap.cs:6719 (Collision Check 결과 윈도우 행 클릭) — 동일
향후 카메라 조회가 필요한 신규 메서드는 본 헬퍼만 호출하면 됩니다.
---
2. publish-build-auto.sh marker hook 3종 추가
handoff.html에는 v0.1.267 사이클에서 5개 marker를 자동 갱신하도록 hook을 구축했지만, HEADER_TITLE_AUTOGEN / FACTORY00_GIT_AUTOGEN / COLLAB_GIT_AUTOGEN 3개 marker는 hook 코드가 빠져 있어 수동 갱신에 의존하고 있었습니다. 이번 사이클에서 자동화 완성.
| marker | 자동 갱신 내용 |
|---|---|
| HEADER_TITLE_AUTOGEN |

기획자 전달 — factory00 진척 종합 (최신 vX.Y.Z · YYYY-MM-DD KST)

자동 갱신 |
| FACTORY00_GIT_AUTOGEN | factory00 자체 repo git log -1 --pretty=format:'%h|%s' 결과 (commit hash + 제목) 자동 표시 |
| COLLAB_GIT_AUTOGEN | 협업자 repo git log -1 --pretty=format:'%h|%ad|%s' 결과 (hash + 날짜 + 제목) 자동 표시 |
구현 패턴
bash에서 git log 결과를 환경변수로 전달 -> python heredoc에서 marker regex로 교체. 결과 저장 시 모든 8개 marker (기존 5 + 신규 3)가 한 번에 처리됩니다.
`bash
F00_LOG_RAW=$(cd "$PROJ" && git log -1 --pretty=format:'%h|%s')
export F00_HASH="${F00_LOG_RAW%%|*}"
export F00_SUBJ="${F00_LOG_RAW#*|}"
# (협업자 repo도 동일 패턴)
`
이제 매 빌드마다 handoff.html이 완전 자동 갱신됩니다. 어시스턴트가 직접 편집해야 하는 부분은 handoff-pm-action.html의 PM 액션 패널 본문(spot-check 다이어트 등)만 남게 됩니다.
---
3. 룰 fix — `spec-vs-codebase-pre-check.md` 변수 scope 검증 추가
v0.1.272 r1에서 camCtrl not in scope 컴파일 에러로 빌드 abort가 발생한 회고를 룰에 반영했습니다.
추가 항목
§2 codebase grep으로 실제 구조 검증 절에 변수 scope 검증 grep 패턴 추가:
`bash
# 신규 메서드가 기존 변수(camCtrl 등)를 참조하려 할 때
# 그 변수가 클래스 필드인지 vs 다른 메서드의 로컬 변수인지 grep으로 확인
grep -nE "^s*(public|private|internal|protected)?s*w+s+camCtrl" Assets/Scripts/Game/Factory00Bootstrap.cs
grep -nE "var camCtrls*=" Assets/Scripts/Game/Factory00Bootstrap.cs
`
매칭이 var camCtrl = ... (로컬) 만 있고 필드 선언이 없으면 신규 메서드는 즉석 조회 패턴 또는 헬퍼 메서드를 사용해야 합니다.
§3 mismatch 분류 표에도 행 추가:
| 상황 | 처리 |
|---|---|
| 신규 메서드가 참조하려는 변수가 클래스 필드 아님 (다른 메서드의 로컬 변수) | 즉석 조회 패턴 사용 또는 동일 패턴 호출이 2회+ 시 헬퍼 메서드 추출 |
향후 신규 메서드 추가 시 본 grep 단계를 따르면 v0.1.272 r1 같은 컴파일 abort를 회피할 수 있습니다.
---
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.csGetCameraViewController() 헬퍼 신규 + 2곳 교체 (~15라인)
- Tools/qa/publish-build-auto.shHEADER_TITLE / FACTORY00_GIT / COLLAB_GIT marker hook 3종 추가 (~60라인 python heredoc 확장)
- .claude/rules/spec-vs-codebase-pre-check.md — 변수 scope 검증 grep + mismatch 분류 행 (~15라인)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.272 -> 0.1.273
---
검증 절차
1. 헬퍼: 부품 더블클릭 시 카메라 포커스 / Collision 결과 항목 클릭 시 카메라 포커스 — 둘 다 정상 작동
2. publish hook: 이번 v0.1.273 빌드 후 handoff.html의 8개 marker 모두 자동 갱신 확인. h1 제목·factory00 commit hash·협업자 pull 정보가 모두 최신 값으로 표시
3. 룰 fix: 다음 신규 메서드 추가 사이클에서 grep 검증 단계 자연스럽게 적용
---
다음 사이클 예정
- v0.1.274 — QA-065 Undo/Redo 드롭다운 P2 검토 답변 (handshake.md 답변 작성) / 잔존 협업자 spec 정리
- v0.1.275~278 — QA-014 PM 회신 받으면 root cause 확정 / 추가 spec 작업
- 43rd stable seal — v0.1.273~278 5~6 사이클 누적 후 봉인 예정

v0.1.272 — v0.1.272 — QA-069 Collision Check 단일/없음 선택 + 결과 별도 창 (탄젠트 제외)

v0.1.272 v0.1.272 — QA-069 Collision Check 단일/없음 선택 + 결과 별도 창 (탄젠트 제외) zip release notes GitHub
협업자 PM 회신 1건 처리
협업자 PM께서 Collision Check 기능을 다음 세 가지 방향으로 개선해 달라고 요청하셨습니다.
1. 선택 개수 분기 확장 — 현재는 2개 이상 선택해야만 동작하지만, 1개 또는 선택 없음 상태에서도 클릭 시 의미 있는 결과가 나오길 원함
2. 탄젠트(면 접촉, 겹침 없음) 제외 — 실제로 겹친 부품만 결과에 포함
3. 결과 별도 윈도우 — 토스트만으로는 5쌍 이상 결과를 보기 어렵고 항목 클릭으로 씬에서 확인하고 싶음
이번 사이클에서 세 가지 모두 처리했습니다.
---
QA-069 fix — `RunCollisionCheck()` + `OpenCollisionResultsSubWindow()`
1. 선택 개수 분기
| 선택 상태 | 검사 동작 |
|---|---|
| 0개 (선택 없음) | 씬 내 전체 부품 pairwise 검사 (모든 부품 쌍) |
| 1개 이상 | 선택 부품 ↔ 씬 내 나머지 모든 부품 검사 |
내부적으로는 먼저 모든 부품의 AABB를 캐싱한 뒤, 모드에 따라 두 종류의 루프(iselectedSet.Contains + IndexOf 가드도 추가했습니다.
2. 탄젠트 제외 — `StrictBoundsOverlap()` (epsilon 0.1mm)
Bounds.Intersects()는 두 박스가 정확히 한 면만 접촉해도 hit으로 처리합니다(inclusive). 협업자 spec은 면 접촉만으로는 겹침이 아니라고 명시했으므로 각 axis에 대해 epsilon(0.1mm)만큼 실제 겹침이 있어야 hit으로 판정하는 헬퍼를 만들었습니다.
`csharp
bool StrictBoundsOverlap(Bounds a, Bounds b)
{
const float eps = 0.1f; // 0.1mm (factory00 단위 mm)
return (a.min.x + eps < b.max.x && a.max.x > b.min.x + eps)
&& (a.min.y + eps < b.max.y && a.max.y > b.min.y + eps)
&& (a.min.z + eps < b.max.z && a.max.z > b.min.z + eps);
}
`
이 변경은 기존 사용자 경험에 약간의 차이를 만들 수 있습니다. v0.1.222 이래 접촉 부품도 hit으로 표시되던 결과가 더 이상 표시되지 않습니다. 그러나 협업자 PM이 명시적으로 요청한 사항이므로 spec 우선 적용입니다.
3. 결과 별도 윈도우 — `OpenCollisionResultsSubWindow()`
기존 _subWindowOverlay 모달 패턴(v0.1.030 "새창에서 보기")을 재사용하여 일관된 UI를 제공합니다.
- 중앙 정렬 다이얼로그, 폭 520px, 최대 높이 480px
- 헤더: "충돌 검사 결과 — N쌍 겹침" + X 닫기 버튼
- 부제: 검사 범위 + 총 검사 쌍 수 안내
- 본문: ScrollView 안에 페어 리스트 (각 행 = 클릭 가능한 Button)
- 항목 클릭 시 동작:
1. 모달 닫기
2. 두 부품 선택 + Inspector 표시
3. 합집합 AABB로 camCtrl.FocusOnBounds() 호출 -> 카메라 자동 포커스
4. "포커스: A ↔ B" 토스트
결과 0건 / 부품 부족 처리
- 씬에 부품 < 2 -> "검사 가능한 부품이 2개 미만입니다" 토스트
- 충돌 0건 -> "충돌 없음 (검사 범위 · N쌍 검사)" 토스트만 (별도 윈도우 X)
- 충돌 1건 이상 -> 토스트 요약 + 별도 윈도우 동시 표시
---
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.csRunCollisionCheck() + StrictBoundsOverlap() + OpenCollisionResultsSubWindow() 신규 약 150라인. 기존 review-collision 핸들러 1줄로 단순화
- Assets/UI/Components/Ribbon.uxmlreview-collision tooltip 갱신 (3 모드 + 카메라 포커스 안내)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.271 -> 0.1.272
---
검증 절차
1. 선택 없음 + Collision 클릭 -> 씬 전체 부품 pairwise 검사 -> 결과 윈도우 표시
2. 부품 1개 선택 + Collision 클릭 -> 선택 ↔ 전체 검사 -> 결과 윈도우 표시
3. 부품 2개 이상 선택 + Collision 클릭 -> 선택끼리 + 선택↔전체 검사 (중복 제거)
4. 결과 윈도우에서 항목 클릭 -> 모달 닫힘 + 두 부품 선택 + 카메라가 두 부품 합집합으로 줌
5. 탄젠트 접촉 부품 (예: 정확히 면이 맞닿은 두 부품) -> 결과에 표시 안 됨 (이전 v0.1.222 -> v0.1.271 까지는 표시됐던 케이스)
---
critic 검토 권장
본 사이클은 약 150라인 신규 코드 + 새 메서드 3개 (Run / Strict / OpenWindow) 추가입니다. cycle-critic-review.md 룰의 "200라인 이상 변경" 조건에는 약간 못 미치지만, 신규 인터페이스(별도 윈도우 + 카메라 포커스 콜백) 도입이라 다음 사이클(v0.1.273)에서 critic 호출이 권장됩니다.
---
다음 사이클 예정
- v0.1.273 — critic 검토 후 잔존 결함 fix + publish-build-auto.sh marker hook 3종 (HEADER_TITLE / FACTORY00_GIT / COLLAB_GIT) 추가
- 42nd stable seal — v0.1.268~273 6사이클 누적 후 봉인 예정 (post-41st 협업자 회신 5건 + 핸드오프 자동화 + critic deferred 종료)

v0.1.271 — v0.1.271 — F10 SSOT 헬퍼 추출 (41st seal critic 중간 결함 deferred 종료)

v0.1.271 v0.1.271 — F10 SSOT 헬퍼 추출 (41st seal critic 중간 결함 deferred 종료) zip release notes GitHub
41st seal critic deferred 결함 처리
41st stable seal(v0.1.267) 봉인 시 critic 검토에서 발견된 중간 결함 1건을 정식 종료 처리했습니다. "F10 binding이 두 곳(Factory00Bootstrap.cs:3531 polling + SettingsPanelViewModel.cs:92 RegisterCallback)에 분산되어 SSOT 헬퍼 추출이 필요할 수 있다"는 critic 지적이었습니다.
검토 결과 — 결함이 아니라 의도된 안전망
코드를 정밀히 검토한 결과, 두 binding은 SSOT 분열이 아니라 PostMessage WM_KEYDOWN 자동화를 위한 의도된 이중 안전망임을 확인했습니다.
- Factory00Bootstrap.cs:3531 (Input.GetKeyDown polling) — UnityEngine.Input 표준 경로
- SettingsPanelViewModel.cs:92 (RegisterCallback) — UI Toolkit 이벤트 경로, focused element가 없으면 root까지 propagate
두 경로 모두 단일 메서드 SettingsVM.Toggle()을 호출합니다. SSOT는 Toggle()이며, 그 안에 150ms _lastToggleTime 시간 throttle(SettingsPanelViewModel.cs:247)이 동시 발화 시 두 번째 호출을 안전하게 차단합니다.
이중 binding이 필요한 이유는 자동화 안전망입니다. 룰 qa-test-by-repro.md §1.2에 따라 PostMessage WM_KEYDOWN 자동화에서 첫 번째 dispatch는 RegisterCallback path로 잘 도달하지만, polling 경로는 Unity Input pipeline의 별도 호출 시점을 캐치할 수 있어 두 경로 모두 유지하는 것이 회귀 안전성을 보장합니다.
처리
- Factory00Bootstrap.cs:3531SettingsPanelViewModel.cs:92에 의도 주석을 강화했습니다. 두 binding이 의도된 이중 안전망이며, SSOT는 Toggle() 단일 메서드 + 150ms throttle임을 명시했습니다.
- 불필요한 Debug.Log 한 줄도 제거했습니다 (Bootstrap.cs:3534 [shortcut] F10 -> SettingsVM.Toggle).
41st seal critic 결함 추적 종료
| 등급 | 항목 | 처리 |
|---|---|---|
| 치명 | 0 | — |
| 중대 | 0 | — |
| 중간 | F10 이중 binding | 본 사이클 deferred 종료 (의도된 안전망 확인 + 주석 강화) |
| 사소 | 주석 ESC->F10 | v0.1.267 즉시 fix 완료 |
41st seal 추적 잔존 결함이 모두 해결되었습니다.
---
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs — F10 polling 주석 강화 + Debug.Log 제거
- Assets/Scripts/UI/SettingsPanelViewModel.cs — RegisterCallback 주석 강화 (SSOT 명시)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.270 -> 0.1.271
---
검증 절차
1. F10 키 누름 -> 설정 패널 열림/닫힘 토글 정상
2. PostMessage WM_KEYDOWN 자동화로 F10 두 번 dispatch -> 한 번만 토글 (150ms throttle)
3. 다른 단축키 회귀 없음 (F11 좌측 패널 / G Gizmo / B BBox / L Lit)
---
다음 사이클 예정
- v0.1.272 — QA-069 Collision Check 단일/없음 선택 + 결과 별도 윈도우 (큰 사이클 ~150라인)
- v0.1.273 — publish-build-auto.sh marker hook 3종 추가 (HEADER_TITLE / FACTORY00_GIT / COLLAB_GIT)
- 42nd stable seal — v0.1.268~273 6사이클 누적 후 봉인 예정

v0.1.270 — v0.1.270 — QA-066 씬 클릭 시 부품 리스트 오토 트래킹 ([설정] 옵션 토글 노출)

v0.1.270 v0.1.270 — QA-066 씬 클릭 시 부품 리스트 오토 트래킹 ([설정] 옵션 토글 노출) zip release notes GitHub
협업자 PM 회신 1건 처리
협업자 PM께서 "씬에서 오브젝트를 클릭했을 때 부품 리스트에서 해당 항목이 자동 선택되고 스크롤도 따라 이동했으면 좋겠다. 부품 리스트 상단에 [[설정]옵션] 버튼을 추가하여 ON/OFF 토글 가능하게 해달라"고 요청하셨습니다.
흥미롭게도 오토 트래킹 동작 자체는 v0.1.030부터 이미 autoTrackingScroll 플래그로 구현되어 있었습니다. 다만 ON/OFF를 토글할 사용자 노출 UI가 없어 사실상 켜진 상태로만 사용되고 있었습니다. 이번 사이클에서는 spec이 요청한 노출 UI를 추가하는 작업이 핵심입니다.
---
QA-066 fix — 부품 리스트 [[설정]옵션] 토글 추가
UI 변경
부품 리스트 상단 툴바에 [설정] 버튼을 추가했습니다. 기존 [펼치기] [접기] 우측에 배치되어 협업자 spec([▼필터] [모두펼치기] [모두접기] [[설정]옵션])의 의도에 맞춰져 있습니다.
`
[펼치기] [접기] [[설정]] <- 신규
`
옵션 메뉴
[설정] 버튼 클릭 시 ContextMenu가 펼쳐지며 다음 항목이 표시됩니다.
`
[[OK]] 씬 클릭 시 부품 리스트 오토 트래킹
`
체크 상태는 현재 autoTrackingScroll 플래그 값을 즉시 반영합니다. 클릭하면 토글되며 상태 변경을 토스트("오토 트래킹 ON" 또는 "OFF")로 안내합니다.
SSOT 정책
협업자 spec은 "ON/OFF 상태는 세션 임시 (앱 재시작 시 ON 기본값)"라고 명시했으나, codebase에는 이미 PlayerPrefs("factory00.auto_tracking_scroll") SSOT가 v0.1.138부터 존재합니다. spec 그대로 세션 임시로 변경하면 SSOT 분열이 발생하므로, 기존 PlayerPrefs 영구 저장 정책을 유지했습니다. 사용자 선호도가 앱 재시작 후에도 보존되어 오히려 UX 측면에서도 우수합니다. 협업자 spec과의 미세한 차이는 향후 라운드에서 답변드릴 예정입니다.
오토 트래킹 동작 (기존 v0.1.030 코드 활용)
씬 클릭 -> PickPartUnderMouse() -> SelectPartFromExternal(picked) 경로에서 이미 다음 처리가 되어 있습니다.
`csharp
if (autoTrackingScroll && _partList != null && _visibleParts != null)
{
int idx = _visibleParts.IndexOf(p);
if (idx >= 0) { try { _partList.ScrollToItem(idx); } catch { } }
}
`
추가 hook 없이 옵션 토글 UI만 노출하면 spec이 요구한 동작이 완성됩니다.
---
변경 파일
- Assets/UI/MainHUD.uxmlparts-toolbarparts-toolbar-options ([설정]) 버튼 추가
- Assets/Scripts/Game/Factory00Bootstrap.csparts-toolbar-options ContextMenu wiring (autoTrackingScroll 토글 + PlayerPrefs 영구)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.269 -> 0.1.270
---
검증 절차
1. 부품 리스트 상단에 [설정] 버튼이 표시되는지 확인
2. [설정] 클릭 -> "[[OK]] 씬 클릭 시 부품 리스트 오토 트래킹" 메뉴 표시
3. 씬에서 부품 클릭 -> 부품 리스트에서 해당 항목이 자동 하이라이트 + 스크롤 이동
4. [설정] 다시 클릭 -> 체크 해제 -> 씬 클릭 시 스크롤 변화 없음 (선택만 변경)
5. 앱 종료 후 재실행 -> 직전 ON/OFF 상태 그대로 유지 (PlayerPrefs 영구)
---
다음 사이클 예정
- v0.1.271 — QA-069 (Collision Check 단일 선택 동작 + 결과 별도 창) / QA-065 (Undo/Redo 드롭다운 P2 검토 답변)
- v0.1.272 — F10 SSOT 헬퍼 추출 (41st seal 중간 deferred) + publish-build-auto.sh HEADER_TITLE / FACTORY00_GIT / COLLAB_GIT marker hook 3종
- 42nd stable seal — v0.1.268~272 5사이클 누적 후 봉인 예정 (post-41st 핸드오프 자동화 + 협업자 PM 회신 다수 fix)

v0.1.269 — v0.1.269 — QA-070 프로젝트 저장 경로 기억 + handoff 다이어트 (PM 18건 확정 반영)

v0.1.269 v0.1.269 — QA-070 프로젝트 저장 경로 기억 + handoff 다이어트 (PM 18건 확정 반영) zip release notes GitHub
협업자 PM 회신 1건 처리 + 협업자 git pull 반영
이번 사이클에서는 두 가지 일이 동시에 진행되었습니다.
먼저, 협업자 PM께서 2026-05-21 새벽 handshake r058 commit (4278c77)에서 누적 18개 QA 항목을 [완료] 완료 확정해 주셨습니다. 사용자 명시("협업자 git pull 했을 때 답변받거나 더이상 유효한 내용 아니면 handoff에서 삭제하여 문서 다이어트")에 따라 handoff-pm-action.html [2] spot-check 박스를 32건 -> 14건으로 정리했습니다.
다음, QA-070 프로젝트 저장 기본 경로 + 경로 기억 기능을 구현했습니다. 협업자 PM께서 "Save As 대화상자가 매번 Windows 다운로드 폴더로 초기화되어 불편하다"고 요청하신 사항입니다.
---
QA-070 fix — 저장 경로 기억 (PlayerPrefs `LastSaveDirectory`)
변경 동작
대화상자 초기 경로 결정에 3순위 fallback 체계를 도입했습니다.
| 우선순위 | 경로 | 적용 시점 |
|---|---|---|
| 1순위 | _currentTwnPath의 디렉토리 | 현재 작업 중인 .twn 파일이 있을 때 |
| 2순위 | PlayerPrefs.LastSaveDirectory | 이전 세션에서 사용자가 선택한 마지막 경로 |
| 3순위 | Application.dataPath/../Project/ | .exe 옆에 자동 생성되는 Project/ 폴더 |
3순위 경로는 폴더가 없으면 자동으로 만들어줍니다. 협업자 spec의 정확한 기본값(.exe 실행 파일 위치 기준 상대 경로 ./Project/)을 따랐습니다.
경로 기억 시점
Save / Save As / Open 대화상자에서 사용자가 경로를 선택해 확정한 직후에 PlayerPrefs.SetString("LastSaveDirectory", ...) 호출 + PlayerPrefs.Save()로 즉시 디스크에 기록합니다. 다음 앱 실행 시 같은 폴더에서 시작합니다.
헬퍼 함수 추출
GetTwnDialogInitDir() + RememberTwnDialogDir(filePath) 두 헬퍼로 추출하여 Open 핸들러와 Save 핸들러에서 동일하게 사용합니다. 향후 신규 다이얼로그 추가 시에도 같은 패턴으로 일관성 유지 가능합니다.
---
handoff-pm-action.html 다이어트
협업자 PM이 r058에서 확정한 18개 항목 (QA-033/035/036/037/041/044/046/047/048/049/051/054/056/057/058/064/067/068)을 spot-check 박스에서 제거했습니다. 남은 14건은 seal별로 정리하여 표시합니다.
| 박스 | 변경 전 | 변경 후 |
|---|---|---|
| [2] spot-check | 누적 32건 | 잔존 14건 (PM 확정 18건은 별도 표시) |
| [2] 38th seal | 12건 | 5건 (QA-007/009/021/031/052) |
| [2] 39th seal | 7건 | 2건 (QA-053/055) |
| [2] 40th seal | 6건 | 5건 (QA-038/039/040/062/063) |
| [2] 41st seal | 7건 | 2건 (QA-042/043) |
PM이 확정한 18건은 박스 하단에 별도로 한 줄로 표시해 협업자가 본인 진행 상황을 빠르게 확인할 수 있도록 했습니다.
---
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.csGetTwnDialogInitDir() + RememberTwnDialogDir() 헬퍼 추출 + Open/Save 핸들러 통합
- wiki/handoff-pm-action.html — [2] spot-check 박스 다이어트 (32 -> 14건)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.268 -> 0.1.269
---
검증 절차
1. 첫 실행: Save As 대화상자 -> /Project/ 폴더가 자동 생성되고 그 폴더에서 시작
2. 임의 경로(예: D:/MyProjects/) 선택 후 저장 -> 저장 성공
3. 앱 종료 후 재실행 -> Save As 다시 누르면 D:/MyProjects/ 에서 시작 (마지막 경로 기억)
4. 외부 URL handoff.html 모바일 확인 -> [2] 박스가 14건으로 정리되어 표시
---
다음 사이클 예정
- v0.1.270 — QA-066 (씬 클릭 -> 부품 리스트 오토 트래킹, [[설정]옵션] 토글)
- v0.1.271 — QA-065 (Undo/Redo 드롭다운 히스토리, P2 검토 답변) / QA-069 (Collision Check 단일 선택)
- v0.1.272 — F10 SSOT 헬퍼 추출 (41st seal 중간 deferred) + publish-build-auto.sh HEADER_TITLE / FACTORY00_GIT / COLLAB_GIT marker hook 3종 추가
- 42nd stable seal — v0.1.268~272 5사이클 누적 후 봉인 예정

v0.1.268 — v0.1.268 — QA-045 Edit Tab 그룹 라벨 + QA-050 F11 패널 완전 접힘

v0.1.268 v0.1.268 — QA-045 Edit Tab 그룹 라벨 + QA-050 F11 패널 완전 접힘 zip release notes GitHub
협업자 PM 회신 2건
QA-045 [P2] — Edit Tab 리본 버튼이 그룹 없이 일렬로 나열되어 있어 가독성이 떨어진다는 보고를 받았습니다. 또한 Cut/Copy/Paste 버튼이 P2 미구현인데도 활성 상태로 노출되어 있어 사용자가 클릭 시 혼란이 있다는 지적도 함께 처리했습니다.
QA-050 [P2] — F11 키로 좌측 패널을 접을 때 패널 내용만 사라지고 24px 폭의 빈 영역이 남아있어 "씬이 확장되지 않은 버그"로 착각된다는 보고를 받았습니다. 협업자 PM께서는 패널이 완전히 접혀 씬 뷰포트가 좌측으로 확장되어야 한다고 요청하셨습니다.
---
QA-045 fix — Edit Tab 4 그룹 분할 + Cut/Copy/Paste 비활성
협업자 spec(studio-edit-tab-summary.md)의 그룹 구분에 맞춰 4개 서브그룹으로 재구성했습니다. Office Ribbon의 표준 UX 패턴(상단에 버튼 가로 배치, 하단에 그룹 라벨 텍스트)을 따랐습니다.
그룹 구성
| 그룹 | 포함 버튼 |
|---|---|
| History | Undo (Ctrl+Z) · Redo (Ctrl+Y) |
| Clipboard | Cut · Copy · Paste (모두 P2 미구현 — 비활성 고정) |
| Selection | Select All (Ctrl+A) · Deselect (Esc) |
| Object | Delete (Del) · Duplicate (Ctrl+D) |
Cut/Copy/Paste 비활성 처리
협업자 PM께서 "P2 미구현인데 클릭 가능 상태로 방치되어 있으니 비활성화해달라"고 요청하셨습니다. 두 단계로 처리했습니다.
1. 시각적: ribbon.uss#edit-cut, #edit-copy, #edit-paste 셀렉터로 opacity 0.35 + 회색 배경 + hover 효과 무력화
2. 기능적: Factory00Bootstrap.cs에서 세 버튼 모두 SetEnabled(false) 호출하여 클릭 자체를 차단
P2 구현 시 USS 셀렉터 + SetEnabled 한 줄만 제거하면 활성화됩니다.
---
QA-050 fix — F11 시 패널 완전 접힘 (씬 좌측 확장)
기존: --size-leftpanel-collapsed: 24px (햄버거 ≡ 클릭 영역 확보 목적). 사용자가 보면 패널 영역이 24px 남아있어 "씬이 확장되지 않은 버그"로 보임.
변경: --size-leftpanel-collapsed: 0px. F11 접기 시 패널 영역이 완전히 사라져 씬 뷰포트가 좌측 0px까지 확장됩니다.
복원 경로
햄버거 ≡ 버튼은 v0.1.170부터 이미 Ribbon 좌측 끝에 존재하므로 (tab-row의 첫 위젯 toggle-left), 접힘 상태에서도 ≡ 클릭으로 패널을 복원할 수 있습니다. F11 단축키도 그대로 동작합니다. 접힘/펼침 변경 시 토스트도 기존처럼 표시됩니다.
---
변경 파일
- Assets/UI/Components/Ribbon.uxmlcmds-edit 4 서브그룹 분할 + Cut/Copy/Paste 버튼 추가
- Assets/UI/Components/ribbon.uss.c-ribbon__subgroup + .c-ribbon__subgroup-label 신규 셀렉터 + Cut/Copy/Paste 비활성 시각 처리
- Assets/UI/Theme/tokens.uss--size-leftpanel-collapsed: 24px -> 0px
- Assets/Scripts/Game/Factory00Bootstrap.cs — Edit Cut/Copy/Paste SetEnabled(false) wire 추가
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.267 -> 0.1.268
---
검증 절차
1. Edit 탭 선택 -> 4개 그룹 (History / Clipboard / Selection / Object)이 라벨과 함께 표시되는지 확인
2. Cut/Copy/Paste 버튼이 회색으로 표시되고 클릭해도 반응 없는지 확인
3. F11 키 -> 좌측 패널이 완전히 사라지고 씬이 좌측 0px까지 확장되는지 확인
4. Ribbon 좌측 ≡ 햄버거 클릭 -> 패널 복원 (320px) 확인
5. F11 재입력 -> 패널 토글 정상 작동
---
다음 사이클 예정
- v0.1.269 — QA-014 PM 회신 받으면 root cause 확정 후 fix / QA-065 Undo/Redo 드롭다운 히스토리 (P2 검토) / QA-066 씬 클릭 시 부품 리스트 오토 트래킹
- v0.1.270~ — 41st seal에서 deferred된 중간 결함 (F10 SSOT 헬퍼 추출) + publish-build-auto.sh HEADER_TITLE / FACTORY00_GIT / COLLAB_GIT marker hook 3종 추가
- 42nd stable seal — v0.1.268~272 5사이클 누적 후 봉인 예정

v0.1.267 — v0.1.267 — 키보드 이동 속도 슬라이더 + URP 투명 적용 + 핸드오프 문서 가독성 개선

v0.1.267 v0.1.267 — 키보드 이동 속도 슬라이더 + URP 투명 적용 + 핸드오프 문서 가독성 개선 zip release notes GitHub
이번 사이클 처리 — 협업자 PM 회신 2건 + 문서 폴리시
QA-042 — 키보드 이동 속도(WASD) 슬라이더 추가
협업자 PM께서 "1인칭 모드(F4)에서 WASD/Space/C 키로 이동할 때 속도를 설정창에서 조절할 수 있도록 해달라"고 요청하셨습니다. 이번 빌드에서 처리했습니다.
구현 내역
- MainHUD.uxml — 설정창 4번째 행으로 slider-fp-speed 슬라이더(범위 0.5~10 m/s, 기본값 2) + label-fp-speed FloatField 추가
- SettingsPanelViewModel.csGetFpSpeed / SetFpSpeed 콜백 추가 + 기존 슬라이더 wiring 패턴(_label* -> _value* rename) 일관 적용
- Factory00Bootstrap.cs — SettingsVM에 콜백 전달 (CameraViewController.fpSpeed 직접 바인딩)
사용성
설정창([설정] 또는 F10)을 여시면 기존 3개 슬라이더(궤도 속도, 패닝 속도, 확대 속도) 아래에 "키보드 이동 속도 (1인칭)" 슬라이더가 추가됩니다. F4로 1인칭 모드 진입 후 W/A/S/D/Space/C 키 이동 시 슬라이더 값에 따라 속도가 변합니다. 궤도 모드는 기존처럼 카메라-타겟 거리에 비례하므로 본 슬라이더 영향 없습니다.
QA-043 — 우클릭 "투명하게 보기" 실제 반투명 적용
협업자 PM께서 "우클릭 메뉴의 '투명하게 보기'를 클릭하면 상태 표시는 바뀌지만 실제 모델은 반투명으로 보이지 않는다"고 보고해주셨습니다. URP/Lit shader의 transparent 모드 활성화에 필요한 속성을 일부만 설정하고 있었던 문제로, 이번 빌드에서 완전히 적용했습니다.
변경 전 (Bootstrap.cs L7437 TogglePartTransparency)
_Surface = 1 한 줄만 설정 -> URP/Lit이 opaque 큐에서 그대로 렌더링되어 알파값이 무시되는 상태였습니다.
변경 후 — URP/Lit transparent 모드 완전 셋업
`csharp
inst.SetFloat("_Surface", 1f); // 0=Opaque, 1=Transparent
inst.SetFloat("_Blend", 0f); // 0=Alpha
inst.SetFloat("_AlphaClip", 0f);
inst.SetFloat("_SrcBlend", (float)UnityEngine.Rendering.BlendMode.SrcAlpha);
inst.SetFloat("_DstBlend", (float)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
inst.SetFloat("_ZWrite", 0f);
inst.DisableKeyword("_SURFACE_TYPE_OPAQUE");
inst.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
inst.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
`
알파값 0.35를 적용하여 반투명으로 표시되며, 렌더 큐도 Transparent로 이동시켜 다른 transparent 오브젝트와 올바른 깊이 정렬이 됩니다.
---
핸드오프 문서 가독성 개선
사용자 요청 "모바일에서 PM 액션 패널이 잘 안 보인다 / 너무 길지 않도록 한다"를 받고 두 단계로 개선했습니다.
1단계 — `handoff.html` 구조 다이어트 (579라인 -> 276라인, 52% 감소)
기존 sec1~9의 본문에는 이미 release-notes로 SSOT가 옮겨진 정보들이 stale 상태로 남아 있었습니다 (Stable Seal 11건 표, Ribbon 45 명령 매트릭스, spec 23/28 카운트 등). 이런 중복 정보를 일괄 제거하고 다음과 같이 단순화했습니다.
- CYCLE_LOG 표는 최근 5건만 노출하고 나머지는 release-notes 링크로 위임
- 협업자 113건 변경 박스는 한 줄로 축소 + 상세는 SSOT 링크
- 본문 sec1~9는 모두 "release-notes 참조" 링크로 대체
- PM 액션 패널만 별도 파일(wiki/handoff-pm-action.html, 41라인 -> 보강 후 약 130라인)로 분리
2단계 — PM 액션 패널 가독성 보강
모바일에서 [2] 박스 제목이 우측으로 잘리고, QA 번호가 점(·)으로만 나열되어 줄바꿈 시 가독성이 떨어지는 문제를 확인했습니다. 다음과 같이 개선했습니다.
- 카드 padding 10->14px, line-height 1.65 적용으로 여백 확보
- [2] 박스 제목을 짧게 ("v0.1.240->266" 잘림 회피) + 부제로 누적 건수 표시
- QA 번호를 콤마(,) 구분으로 자연스러운 줄바꿈
- 각 항목에 친절한 설명 한 줄 추가 (단순 나열 -> 의도 전달)
- 빠른 다운로드 박스에 zip 크기·날짜·영구 보존판 명시
---
빌드 자동화 hook (publish-build-auto.sh marker 5종)
매 빌드마다 handoff.html이 자동 갱신되도록 5개 marker를 도입했습니다. 어시스턴트가 매 사이클 핸드오프 문서를 수동 편집하던 부담이 사라집니다.
| marker | 자동 갱신 내용 |
|---|---|
| BUILD_META_AUTOGEN | 최종 갱신 일시 + 최신 빌드 버전 |
| BUILD_VERSION_AUTOGEN | 현재 작업 버전 + 빌드 제목 (build-title.txt 1줄) |
| CYCLE_LOG_AUTOGEN | 사이클 표에 신규 행 prepend (최근 5건 유지, 중복 회피) |
| PM_ACTION_AUTOGEN | wiki/handoff-pm-action.html 통째 삽입 (어시스턴트가 갱신할 SSOT) |
| PM_DOWNLOAD_AUTOGEN | 빠른 다운로드 박스의 vX.Y.Z zip 링크 |
또한 매 빌드 시 협업자 repo(/mnt/c/tmp/codeless-dt)도 자동 git pull되어, 신규 commit이 발견되면 어시스턴트가 다음 사이클에서 handoff-pm-action.html을 다이어트(답변 받은 항목·spot-check PASS 받은 항목 제거)할 수 있습니다.
---
변경 파일
- Assets/UI/MainHUD.uxml — 설정창에 slider-fp-speed 행 추가
- Assets/Scripts/UI/SettingsPanelViewModel.csGetFpSpeed / SetFpSpeed 콜백 + 슬라이더 wiring
- Assets/Scripts/Game/Factory00Bootstrap.cs — SettingsVM 콜백 전달 + TogglePartTransparency URP transparent 완전 적용
- wiki/handoff.html — 579->276라인 다이어트 + marker 5종 도입
- wiki/handoff-pm-action.html — 가독성 보강 (카드 padding, 친절한 설명, 모바일 줄바꿈 친화)
- Tools/qa/publish-build-auto.sh — PM_ACTION + PM_DOWNLOAD marker hook + 협업자 git pull
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.266 -> 0.1.267
---
검증 절차
1. 설정창([설정] 또는 F10)을 열고 4번째 슬라이더 "키보드 이동 속도 (1인칭)"가 표시되는지 확인
2. F4로 1인칭 모드 진입 -> W 키 이동 시 슬라이더 값에 따라 속도 변화 확인 (기본값 2 m/s)
3. 부품 우클릭 -> "투명하게 보기" 클릭 -> 모델이 실제로 반투명으로 표시되는지 확인 (알파 0.35)
4. 외부 URL(https://os-file-server.tail2b816d.ts.net/wiki/handoff.html)에서 PM 액션 패널이 모바일에서 잘리지 않고 잘 보이는지 확인
---
다음 사이클 예정
- v0.1.268 — QA-014 PM 회신 받으면 root cause 확정 후 fix / QA-045 Edit Tab 그룹 라벨 / QA-050 F11 씬 미확장
- v0.1.269 — 41st stable seal 검토 (v0.1.263~268 일괄 봉인)

v0.1.266 — v0.1.266 — QA-049 Esc->F10 + QA-064 복제 highlight 잔존

v0.1.266 v0.1.266 — QA-049 Esc->F10 + QA-064 복제 highlight 잔존 zip release notes GitHub
협업자 PM 회신 2건
QA-049 [P2] — Esc 키 충돌 (Deselect vs 설정 팝업). PM 정책: 설정 -> F10, Esc = Deselect 전용.
QA-064 [P2] — 복제 후 원본 click 시 복제본에도 선택 highlight 표시.
QA-049 fix — Esc -> F10
3 위치 변경:
- Bootstrap.cs:3470 Update polling: KeyCode.Escape -> KeyCode.F10
- SettingsPanelViewModel.cs:86 RegisterCallback: KeyCode.Escape -> KeyCode.F10
- Ribbon.uxml:28 tooltip: "설정 (ESC)" -> "설정 (F10)"
Esc는 이제 Deselect 전용. 설정 팝업은 F10 / [설정] 버튼 click / Toggle API.
QA-064 root cause 확정
HighlightSelectedParts -> ApplyMaterialHighlight(parts) 호출. 호출 전 ClearMaterialHighlight() 없음 -> _materialBackups에 이전 backup 누적.
TickMaterialHighlightPulse()가 매 frame _materialBackups 전체 순회 -> 선택 해제된 부품 + 복제본 renderer의 emission도 변경 -> 시각적 "highlight 잔존".
복제 직후 원본 click 시:
1. 복제본의 backup이 v0.1.243 이전 selection 또는 직전 copy 작업의 잔재로 남아있음
2. 원본 click -> HighlightSelectedParts([원본]) -> backup 추가 (원본만)
3. 이전 backup 미정리 -> 복제본도 TickPulse가 emission 변경
QA-064 fix
ApplyMaterialHighlight() 진입 시 ClearMaterialHighlight() 호출:
`csharp
void ApplyMaterialHighlight(List parts) {
ClearMaterialHighlight(); // 이전 backup 일괄 복원
foreach (var p in parts) {
// 새 selection backup 추가
}
}
`
backup 누적 차단 -> 선택 해제된 부품의 stale highlight 영구 차단.
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~5라인) — ESC->F10 + ApplyMaterialHighlight ClearMaterialHighlight 추가
- Assets/Scripts/UI/SettingsPanelViewModel.cs (1라인) — KeyCode 변경
- Assets/UI/Components/Ribbon.uxml — tooltip 변경
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.265 -> 0.1.266
검증 시나리오
QA-049
1. 부품 선택 -> Esc -> Deselect (선택 해제) / 설정 팝업 X
2. F10 -> 설정 팝업 열림
3. F10 다시 -> 팝업 닫힘
4. 설정창 열린 상태 -> Esc -> 팝업 닫힘 X (Deselect만 처리) — 추후 추가 fix 가능
QA-064
1. 부품 selection -> Ctrl+D -> 복제본 생성 (선택 = 복제본)
2. 원본 click -> 원본만 highlight (복제본 highlight 사라짐)
3. 복제본 click -> 복제본만 highlight
다음 사이클
- v0.1.267 — QA-042 (카메라 속도 설정) + QA-043 (투명 실제 적용)
- v0.1.268 — QA-014 (PM 회신 받으면)
- v0.1.269 — 41th stable seal 검토 (v0.1.263~268)
협업자 git origin/main = local.

v0.1.265 — v0.1.265 — QA-048 Duplicate 오프셋 누적

v0.1.265 v0.1.265 — QA-048 Duplicate 오프셋 누적 zip release notes GitHub
협업자 PM 회신
QA-048 [P2] — 반복 Duplicate 시 동일 오프셋 위치 겹침. PM 요청: 매 복제마다 offset 가산.
root cause
DuplicateCommand.Execute() L6968:
`csharp
_duplicateGo.transform.position = origGo.transform.position + origGo.transform.right * 50f;
`
원본 기준 항상 +50mm -> N회 복제 -> 모두 같은 위치 겹침.
fix — origId 카운터 누적
`csharp
Dictionary _duplicateCount = new(); // 세션 동안 유지
// DuplicateCommand.Execute() 안
int dupCount = 1;
string origId = _original.id ?? "";
if (!string.IsNullOrEmpty(origId)) {
_host._duplicateCount.TryGetValue(origId, out dupCount);
dupCount++;
_host._duplicateCount[origId] = dupCount;
}
_duplicateGo.transform.position = origGo.transform.position + origGo.transform.right * (50f * dupCount);
`
| 복제 횟수 | 오프셋 |
|---|---|
| 1회 | +50mm |
| 2회 | +100mm |
| 3회 | +150mm |
| ... | ... |
원본 기준 누적 (체이닝 아님 — 협업자 spec "원본 위치 + offset(N)" 패턴).
.twn 로드 시 reset
ClearAllRuntimeComponents()_duplicateCount?.Clear() 추가. 새 .twn 로드 시 카운터 초기화.
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+10라인) — _duplicateCount Dictionary + DuplicateCommand 오프셋 누적 + ClearAllRuntimeComponents reset
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.264 -> 0.1.265
검증 시나리오
1. 부품 선택 -> Ctrl+D 1회 -> +50mm 우측
2. 동일 원본 -> Ctrl+D 2회 -> +100mm 우측 (이전 복제본과 +50mm 차이)
3. Ctrl+D 3회 -> +150mm 우측
4. 다른 원본 선택 -> Ctrl+D 1회 -> +50mm (origId별 독립 카운터)
5. New 또는 .twn 로드 -> 카운터 reset -> +50mm 부터 다시 시작
6. Undo (Ctrl+Z) -> 복제본 사라짐 (카운터는 유지 — 사용자 의도 모호하므로 보수적)
다음 사이클
- v0.1.266 — QA-064 (복제 후 원본 click 시 복제본 선택 오동작) + QA-049 (Esc 충돌)
- v0.1.267 — QA-042 카메라 속도 설정 / QA-043 투명 실제 적용
- v0.1.268 — QA-014 (PM 회신)
협업자 git origin/main = local.

v0.1.264 — v0.1.264 — QA-067 SignalSim 스크롤 보존 + QA-068 Gizmo 다중 이동

v0.1.264 v0.1.264 — QA-067 SignalSim 스크롤 보존 + QA-068 Gizmo 다중 이동 zip release notes GitHub
협업자 PM 회신 2건
QA-067 [P1] — 리스트 갱신 시 스크롤 최상단 초기화 (Signal Simulator / 부품 리스트)
QA-068 [P1] — 다중 선택 오브젝트 Gizmo 이동 시 마지막 1개만 이동
QA-068 root cause 확정
UpdateGizmoTargets() L4148:
`csharp
var ts = new List(1);
if (_selectedPart != null && _selectedPart.cachedTransform != null)
ts.Add(_selectedPart.cachedTransform); // <- 단일만 전달
gz.SetTargets(ts);
`
RuntimeGizmo는 이미 _targets 전체에 동일 delta 적용 (L816 foreach). 호출 측 누락이 root cause.
QA-068 fix
`csharp
var ts = new List();
if (_selectedParts != null && _selectedParts.Count > 0)
{
foreach (var p in _selectedParts)
if (p?.cachedTransform != null) ts.Add(p.cachedTransform);
}
else if (_selectedPart?.cachedTransform != null)
{
ts.Add(_selectedPart.cachedTransform);
}
gz.SetTargets(ts);
`
- 다중 선택 시: 모든 부품 transform 전달 -> RuntimeGizmo가 모두 동일 delta 이동
- 단일 선택 시: 기존 동작 그대로
- gizmo center는 RuntimeGizmo.SetTargets 안에서 평균 계산 (_targets[0] 또는 mean)
QA-067 root cause
SignalSimulatorPanel.Render() 100ms 폴링 시 _root.Clear() -> ScrollView 재생성 -> scrollOffset=0.
QA-067 fix
`csharp
public void Render() {
Vector2 savedScroll = Vector2.zero;
var oldScroll = _root.Q();
if (oldScroll != null) savedScroll = oldScroll.scrollOffset;
_root.Clear();
...
var scroll = new ScrollView();
_root.Add(scroll);
if (savedScroll != Vector2.zero) {
scroll.RegisterCallback(evt => {
scroll.scrollOffset = savedScroll;
});
}
}
`
- Render() 전 기존 ScrollView grep + scrollOffset 저장
- 신규 ScrollView 생성 후 GeometryChangedEvent에서 1회 복원 (layout 완료 시점)
- savedScroll=Vector2.zero (초기 상태)이면 복원 skip — 첫 Render는 정상 최상단
부품 리스트 스크롤 영향
부품 리스트 ListView는 itemsSource 변경 시 자체 스크롤 보존 (Unity ListView 기본). SignalSimulator만 ScrollView 직접 재생성 패턴이므로 본 사이클 fix 대상.
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~10라인) — UpdateGizmoTargets 다중 처리
- Assets/Scripts/Communication/Modbus/SignalSimulatorPanel.cs (~12라인) — scrollOffset 저장/복원
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.263 -> 0.1.264
검증 시나리오
QA-068
1. Ctrl+A 또는 drag-select로 다중 부품 선택
2. Gizmo translate handle drag -> 모든 부품 동시 이동 (이전: 1개만)
3. Ctrl+Z -> 모든 부품 원위치 복원 (TransformCommand 호환)
4. 단일 선택 시 회귀 없음
QA-067
1. SignalSim 열기 -> 컴포넌트 다수 표시 -> 스크롤 중간으로
2. 100ms 폴링으로 Render() 호출 시 스크롤 위치 유지 (이전: 최상단 초기화)
3. 부품 추가/삭제 후 Render -> 스크롤 보존
4. 첫 Render는 최상단 (정상)
다음 사이클
- v0.1.265 — QA-014 (PM 회신 받으면)
- v0.1.266 — QA-042 (카메라 속도 설정) / QA-043 (투명 실제 적용) / QA-064 (복제 원본 click 오동작)
- v0.1.267 — QA-069 Collision 단일 선택 + 결과 별도 창
협업자 git origin/main = local.

v0.1.263 — v0.1.263 — critic 중간/사소 잔존 일괄 fix (post-40th polish)

v0.1.263 v0.1.263 — critic 중간/사소 잔존 일괄 fix (post-40th polish) zip release notes GitHub
critic 잔존 처리
| 등급 | 결함 | 처리 |
|---|---|---|
| 중간-1 | CoilEnable=0 미할당 시 행 자체 숨김 -> "Enable 제어 없음" vs "코일 미설정" 구분 불가 | AddCoilToggleRow에 "(미할당)" disabled 라벨 표시 |
| 중간-2 | _lastHasSelection=true 주석 "초기 상태와 다르게" 반대 방향 기술 | 주석 명확화 — default=false로 변경 시 회귀 발생 명시 |
| 중간-3 | SignalSim Render 코드 추적 비용 (Q3 검토만, 회귀 없음) | 클래스 헤더 주석 갱신 (v0.1.260/262 추가 명시) |
| 사소-1 | SignalSim 클래스 주석 v0.1.259 / a.CoilEnable 참조 불일치 | 헤더 v0.1.260 명시 추가 |
중간-1 — AddCoilToggleRow 미할당 안내
기존:
`csharp
void AddCoilToggleRow(...) {
if (coilAddr <= 0) return; // 행 숨김 -> 사용자 디버깅 부담
...
}
`
신규:
`csharp
void AddCoilToggleRow(...) {
if (coilAddr <= 0) {
// "{label} (미할당)" disabled + "Inspector -> Coil 번호 설정" hint
return;
}
...
}
`
- 회색 italic 라벨 + 우측 안내 "Inspector -> Coil 번호 설정"
- 사용자가 "Enable 제어 없음 = 코일 미설정"임을 즉시 인지
중간-2 — _lastHasSelection 주석 강화
default=true 의미가 "초기 상태와 다르게 -> 강제 갱신"인데 반대 방향으로 적혀있어 향후 false 변경 위험. 주석에 회귀 시나리오 명시 (default=false 변경 시 SetEnabled 호출 누락 -> uxml enabled=true 잔존).
사소-1 — SignalSim 클래스 헤더 주석 정정
`
// v0.1.259 — QA-040 fix
// v0.1.260 — QA-038: ServoAxisActuator.CoilEnable 신설 + BuildServoControls "Enable" 토글 추가 <- 추가
// v0.1.262 — critic 중대 3건 fix <- 추가
`
변경 파일
- Assets/Scripts/Communication/Modbus/SignalSimulatorPanel.cs (~20라인) — 미할당 안내 라벨 + 클래스 헤더 주석
- Assets/Scripts/Game/Factory00Bootstrap.cs (~5라인) — _lastHasSelection 주석
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.262 -> 0.1.263
검증 시나리오
- ServoAxis 부착 -> Inspector CoilEnable=0 (default) -> SignalSim 팝업 "Enable (미할당)" + "Inspector -> Coil 번호 설정"
- Inspector에서 CoilEnable=100 입력 -> SignalSim 팝업에 정상 토글 행 표시
- 시작 직후 (선택 없음) -> Delete/Duplicate 버튼 grey (회귀 없음)
다음 사이클
- v0.1.264 — QA-067 (리스트 갱신 시 스크롤 초기화) + QA-068 (Gizmo 다중 선택)
- v0.1.265 — QA-014 (PM 회신 받으면)
협업자 git origin/main = local.

v0.1.262 — v0.1.262 — critic 중대 3건 fix (40th seal 직전)

v0.1.262 v0.1.262 — critic 중대 3건 fix (40th seal 직전) zip release notes GitHub
critic 결과 (v0.1.258~261)
| 등급 | 건수 | 처리 |
|---|---|---|
| 치명 | 0 | — |
| 중대 | 3 | 본 사이클 모두 fix |
| 중간 | 3 | 다음 사이클 (CoilEnable 미할당 안내·_lastHasSelection 주석·Color helper rename 검토) |
| 사소 | 2 | 다음 사이클 |
판정: PASS (v0.1.262 fix 후).
중대-1 fix — SignalSim 폴링 중복 차단
기존:
`csharp
StopPolling() { _pollSchedule?.Pause(); _pollSchedule = null; }
StartPolling() { StopPolling(); _pollSchedule = _root.schedule.Execute(...).Every(100); }
`
-> Toggle 반복 시 이전 schedule 인스턴스가 내부 큐에 잔존 가능성.
신규:
`csharp
StartPolling() {
if (_pollSchedule == null) _pollSchedule = _root.schedule.Execute(...).Every(100);
else _pollSchedule.Resume();
}
StopPolling() { _pollSchedule?.Pause(); }
`
-> 단일 인스턴스 Pause/Resume 재사용. 중복 발화 0.
중대-2 fix — SignalControlPopup dangling actuator ref
부품 삭제 후 팝업 잔존 시 토글이 stale actuator의 CoilForward 발행 -> 의도치 않은 이벤트.
`csharp
void PruneDanglingPopup() {
string popupId = _activePopup.ComponentId; // "ownerId/compId"
// _parts에서 owner.{Sensors|Actuators|Pneumatic|Rotary} 안 compId 존재 확인
if (!alive) CloseActivePopup();
}
`
100ms 폴링 시점에 호출 -> 부품 삭제 후 최대 100ms 안 팝업 자동 닫힘. SignalControlPopup.ComponentId public 노출.
중대-3 fix — Enable ReadBit 실패 stale edge
기존:
`csharp
try { nowEnable = _modbus.ReadBit(...); }
catch { nowEnable = a.Enabled; } // 이전 상태 유지
...
_lastEnable[ek] = nowEnable; // <- 실패 구간 동안 prev 누적 갱신
`
-> 실패 후 첫 성공 시 prev가 stale -> edge 누락/잘못 발화.
신규:
`csharp
try { nowEnable = _modbus.ReadBit(...); }
catch { continue; } // <- 본 actuator 이번 frame skip (_lastEnable 미갱신)
`
-> 다음 성공 시 prev=마지막 성공값 -> 정상 edge.
변경 파일
- Assets/Scripts/Communication/Modbus/SignalSimulatorPanel.cs (~45라인) — Pause/Resume 재사용 + PruneDanglingPopup + ComponentId public
- Assets/Scripts/Plc/ActuatorPlcBridge.cs (~3라인) — ReadBit catch -> continue
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.261 -> 0.1.262
검증 시나리오
중대-1
- SignalSim Toggle/Show/Hide 반복 -> 폴링 인스턴스 1개만 유지
- Render() 호출 빈도 100ms 정확 (이중 50ms 발화 X)
중대-2
- SignalSim 열기 -> 부품 click -> 팝업 열림
- 다른 곳에서 해당 부품 Delete -> 100ms 이내 팝업 자동 닫힘
- 팝업 안 토글 click 시점 = 부품 삭제 전이면 정상 발행, 삭제 후면 닫혀서 발행 0
중대-3
- ModbusTCP 연결 끊김 시 actuator Enable 코일 ReadBit 실패 -> 정상 무동작
- 연결 복귀 첫 frame -> prev=마지막 성공값 -> 정상 edge 동작
다음 단계
- v0.1.263 — 40th stable seal 봉인 (v0.1.258~262 5 사이클 + release notes + commit)
- v0.1.264 — 중간-1/2/3 + 사소 fix (CoilEnable 안내 라벨·주석·rename)
- v0.1.265 — QA-014 (PM 회신)
협업자 git origin/main = local.

v0.1.261 — v0.1.261 — QA-046 Delete/Duplicate 버튼 selection 의존 활성화

v0.1.261 v0.1.261 — QA-046 Delete/Duplicate 버튼 selection 의존 활성화 zip release notes GitHub
협업자 PM 회신
QA-046 [P2] — 미선택 상태에서 Delete/Duplicate 버튼 활성 유지 (스펙 위반).
fix
UpdateEditButtonsEnabled() 헬퍼 + Update polling
`csharp
Button _editDeleteBtnRef;
Button _editDupBtnRef;
bool _lastHasSelection = true; // 초기 강제 갱신 트리거
void UpdateEditButtonsEnabled()
{
bool hasSelection = _selectedPart != null
|| (_selectedParts != null && _selectedParts.Count > 0);
if (hasSelection == _lastHasSelection) return;
_lastHasSelection = hasSelection;
if (_editDeleteBtnRef != null) _editDeleteBtnRef.SetEnabled(hasSelection);
if (_editDupBtnRef != null) _editDupBtnRef.SetEnabled(hasSelection);
}
`
Update() 첫 부분에서 호출. 비교 후 변화 시만 SetEnabled (오버헤드 0).
selection 진입점 다수 -> polling 일관
selection 변경처:
- 씬 클릭 (PickPartUnderMouse)
- 부품 리스트 click
- Ctrl+A (Select All)
- drag-select
- Esc (Deselect)
- 컨텍스트 메뉴 select
위 5+ 경로에 각각 helper 호출 추가 vs Update polling — polling이 단순 + 무회귀.
함께 처리된 답변 (handshake.md에 명시)
- QA-062 (Edit Tab 툴팁): 코드 검증 — 모든 버튼에 tooltip 이미 존재 (Ribbon.uxml L49~54). 협업자 v0.1.240 보고 -> 이후 fix 완료된 듯. 별도 변경 X.
- QA-063 (다중 선택 Delete 미동작): v0.1.252 BatchDelete (DeleteCommand List)에서 fix 완료. 별도 변경 X.
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+15라인) — Button ref 저장 + UpdateEditButtonsEnabled helper + Update 호출
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.260 -> 0.1.261
검증 시나리오
QA-046
1. 시작 직후 (선택 없음) -> Delete/Duplicate 버튼 grey (비활성)
2. 부품 클릭 (선택) -> 두 버튼 활성
3. Esc (Deselect) -> 두 버튼 다시 비활성
4. Ctrl+A -> 모두 활성
5. 키보드 D 키도 동일 (Inspector 의존 없음)
다음 사이클
- v0.1.262 — 40th stable seal 검토 (v0.1.258~261 4 사이클)
- v0.1.263 — QA-014 (PM 회신 받으면)
- v0.1.264 — QA-067 (리스트 갱신 시 스크롤 초기화) + QA-068 (Gizmo 다중 선택)
협업자 git origin/main = local.

v0.1.260 — v0.1.260 — QA-038 ServoAxisActuator.CoilEnable 신설

v0.1.260 v0.1.260 — QA-038 ServoAxisActuator.CoilEnable 신설 zip release notes GitHub
협업자 PM 회신
QA-038 [P1] — Signal Simulator 서보축 제어 항목에 Enable 누락. spec: Enable / MoveForward / MoveBackward / TargetPosition.
설계
데이터 (ServoAxisActuator.cs)
`csharp
// ── Modbus 매핑 (직렬화) ──
public int CoilEnable = 0; // 신규 (default 0 — 미할당)
// ── 런타임 (직렬화 제외) ──
[System.NonSerialized] public bool Enabled = true; // default true (CoilEnable=0 시 영원히 true — 기존 호환)
`
.twn 직렬화 영향: JsonUtility는 신규 필드를 default 0으로 자동 채움 -> migration 불필요. 기존 .twn 파일 로드 시 CoilEnable=0 (미할당) 상태로 호환.
ActuatorPlcBridge.cs
`csharp
if (a.CoilEnable > 0)
{
bool nowEnable = _modbus.ReadBit($"COIL:{a.CoilEnable}");
bool prevEnable = _lastEnable[ek];
if (prevEnable && !nowEnable) a.CommandStop(); // falling edge -> 강제 정지
a.Enabled = nowEnable;
_lastEnable[ek] = nowEnable;
}
// Enabled 가드 — Disabled 시 Forward/Backward/Stop/Home Coil polling skip
if (a.Enabled)
{
PollCoilEdge(a.ActuatorId, a.CoilForward, ...);
...
}
`
- CoilEnable=0 미할당 시 항상 활성 (기존 동작)
- Level 추적 (rising/falling 모두)
- Falling edge (Enable OFF) -> 즉시 CommandStop
- Disabled 시 Command Coil polling 자체 차단 (이중 가드)
Inspector (Factory00Bootstrap.cs)
RenderServoAxisCard Coil 행 4개 -> 5개:
`
SensorFloatField(card, "Coil Enable", a.CoilEnable, ...);
SensorFloatField(card, "Coil Fwd", a.CoilForward, ...);
...
`
Signal Simulator (SignalSimulatorPanel.cs)
BuildServoControls:
`csharp
AddCoilToggleRow(parent, "Enable", a.CoilEnable);
AddCoilToggleRow(parent, "MoveForward", a.CoilForward);
...
`
.twn 호환성 검증
| 케이스 | 동작 |
|---|---|
| v0.1.259 이전 .twn 로드 | CoilEnable=0 (default) -> Enabled=true -> 기존 동작 |
| v0.1.260 신규 저장 | CoilEnable 필드 추가 직렬화 |
| v0.1.259로 다운그레이드 후 로드 | CoilEnable 필드 무시 -> 기존 호환 |
JsonUtility 동작: 미지정 필드 default 0, 누락 시 ignore. 양방향 호환.
변경 파일
- Assets/Scripts/Actuators/ServoAxisActuator.cs (+8라인) — CoilEnable / Enabled 필드
- Assets/Scripts/Plc/ActuatorPlcBridge.cs (+18라인) — _lastEnable + CoilEnable 처리
- Assets/Scripts/Game/Factory00Bootstrap.cs (+1라인) — Inspector "Coil Enable" 행
- Assets/Scripts/Communication/Modbus/SignalSimulatorPanel.cs (+1라인) — Signal Simulator "Enable" 토글
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.259 -> 0.1.260
검증 시나리오
1. ServoAxis 부착 -> Inspector 5개 코일 + 1 Register 표시 (Coil Enable 신규)
2. Signal Simulator 제어 팝업 -> Enable 토글 표시
3. CoilEnable=0 (default) -> Enable 토글 비활성 (행 자체 숨김 — coilAddr<=0 가드)
4. Inspector에서 CoilEnable=100 입력 -> Enable 토글 표시
5. PLC Enable OFF -> falling edge -> actuator 즉시 정지 + Command Coil polling 차단
6. PLC Enable ON -> Command Coil 정상 동작
다음 사이클
- v0.1.261 — Signal Simulator 코일 현재값 SSOT (ModbusDataModel polling)
- v0.1.262 — 40th stable seal 검토 (v0.1.258~261)
- v0.1.263 — QA-014 (PM 회신 받으면)
협업자 git origin/main = local. QA-014 PM 회신 계속 대기.

v0.1.259 — v0.1.259 — QA-040/039 Signal Simulator UX 개편 P1

v0.1.259 v0.1.259 — QA-040/039 Signal Simulator UX 개편 P1 zip release notes GitHub
협업자 PM 회신
QA-040 [P1] — Signal Simulator 메인 창 = read-only 모니터 / 컴포넌트 이름 클릭 -> 제어 창 팝업 분리 (PM spec r003).
QA-039 [P2] — 100ms 폴링 자동 갱신 요청.
설계
메인 패널 (read-only 모니터)
기존 단일 패널에서 토글/입력 위젯 모두 제거. 컴포넌트 단위 행:
- 이름 (클릭 가능 Button — 클릭 시 SignalControlPopup 열림)
- 현재 상태 텍스트 (read-only Label)
- Sensor: FinalOutput -> "DETECT" / "—"
- Servo: State + "{CurrentPos:F2}m"
- Pneumatic: State (Forward/Backward/AtA/AtB)
- Rotary: State + "{CurrentAngle:F0}°"
제어 창 팝업 (SignalControlPopup class)
`csharp
public class SignalControlPopup
{
public enum ComponentKind { Sensor, Servo, Pneumatic, Rotary }
public void Show(VisualElement parent) { ... }
public void Close() { ... }
}
`
- 메인 패널 좌측 (right: 410px) 280x480 위젯
- 헤더: "{Kind} · {componentId}" + X 닫기 버튼
- ScrollView 안에 코일 토글 + Reg 입력 (기존 동작 그대로 이양)
- 다른 컴포넌트 click 시 자동 close + reopen (CloseActivePopup)
100ms 폴링 (QA-039)
`csharp
_pollSchedule = _root.schedule.Execute(() => { if (IsVisible) Render(); }).Every(100);
`
Toggle()/Show()에서 시작, Hide()/Close()에서 Pause.
Rotary 추가
기존 코드는 Servo / Pneumatic만 렌더. v0.1.161+ RotaryActuator도 추가.
QA-038 별도 사이클
ServoAxisActuator.CoilEnable 데이터 필드 신설 필요 (현재 4개 — Forward/Backward/Stop/Home). .twn 직렬화 영향 분석 필요. v0.1.260+ 별도 사이클 예약.
변경 파일
- Assets/Scripts/Communication/Modbus/SignalSimulatorPanel.cs (291 -> 430+ 라인 전면 재작성 + SignalControlPopup class 신설)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.258 -> 0.1.259
검증 시나리오
QA-040 분리
1. Signal Simulator 패널 열기 -> 컴포넌트 목록 read-only 표시
2. 컴포넌트 이름 click -> 우측에 제어 팝업 열림
3. 팝업 코일 토글 -> ModbusSignalChangedEvent 발행 (기존 동작)
4. 다른 컴포넌트 click -> 기존 팝업 close + 새 팝업 open
5. X click -> 팝업 닫힘
QA-039 자동 갱신
- 부품 추가 -> 100ms 이내 메인 패널에 표시
- Sensor 감지 상태 변경 -> 100ms 이내 "DETECT" 토글
- Servo 위치 갱신 -> "0.50m" 등 실시간 표시
코일 현재값 SSOT (v0.1.260 P2 예약)
현재는 컴포넌트 자체 상태만 표시. 코일 ON/OFF는 별도 ModbusDataModel SSOT 필요 — 다음 사이클에서 처리.
다음 사이클
- v0.1.260 — QA-038 ServoAxisActuator.CoilEnable 신설 (데이터 + Inspector + Bridge + .twn migration)
- v0.1.261 — Signal Simulator 코일 현재값 SSOT (ModbusDataModel polling)
- v0.1.262 — QA-014 (PM 회신 받으면)
협업자 git origin/main = local.

v0.1.258 — v0.1.258 — critic 중간-1 fix · Actuator Color helper

v0.1.258 v0.1.258 — critic 중간-1 fix · Actuator Color helper zip release notes GitHub
critic 중간-1 (v0.1.253 잔존)
RenderServoAxisCard L5739 + RenderRotaryCard L5624 — ActuatorState switch + new Color(...) 4개 매 Inspector 갱신 시 재할당. 0.25s 주기 호출 누적.
fix — GetActuatorStateColor 정적 helper
`csharp
static readonly Color _stColorForward = new Color(0.45f, 0.85f, 0.45f, 1f);
static readonly Color _stColorBackward = new Color(0.45f, 0.85f, 0.95f, 1f);
static readonly Color _stColorAtLimit = new Color(0.95f, 0.45f, 0.45f, 1f);
static readonly Color _stColorHoming = new Color(0.95f, 0.75f, 0.30f, 1f);
static Color GetActuatorStateColor(ActuatorState s, Color fallback)
{
switch (s) { ... }
}
`
- Color 인스턴스 정적 캐시 (재할당 0)
- ServoAxisCard / RotaryCard 동일 helper 사용 (DRY)
- AtRls / AtFls 동일 색상 (case fall-through)
- 결과 동작 무회귀 — 색상 매핑 그대로
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~25라인 -> helper 추가 + 2개 switch 제거)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.257 -> 0.1.258
검증 시나리오
- Servo Inspector 표시 -> 상태 색상 정상 (이전 동일)
- Rotary Inspector 표시 -> 상태 색상 정상
- Inspector 0.25s 주기 갱신 시 GC alloc 0
다음 사이클
- v0.1.259 — QA-040 Signal Simulator UX 개편 spec 분석 + P1 착수
- v0.1.260 — QA-014 (PM 회신 받으면)
협업자 git origin/main = local. QA-014 PM 회신 계속 대기.

v0.1.257 — v0.1.257 — critic 치명-1 + 중대 2건 fix (39th stable seal 직전)

v0.1.257 v0.1.257 — critic 치명-1 + 중대 2건 fix (39th stable seal 직전) zip release notes GitHub
critic 코드리뷰 결과 (v0.1.251~256)
| 등급 | 건수 | 처리 |
|---|---|---|
| 치명 | 1 | DeleteCommand SetActive 정합성 주석 강화 |
| 중대 | 2 | RaycastAll -> NonAlloc · 토스트 카운트 mismatch |
| 중간 | 1 | RenderRotaryCard Color switch (다음 사이클) |
판정: PASS (v0.1.257 fix 후).
치명-1 정합성 주석
Factory00Bootstrap.cs:7200 DeleteCommand.Execute() SetActive(false) — 협업자 spec QA-021 ④ "삭제 시 물리·이벤트·폴링 모두 사라짐" 정합. v0.1.172 SetPartVisible 코멘트 "SetActive 금지"는 *visibility toggle* 도메인 한정.
주석 추가:
- Delete = SetActive(false) — 물리/Actuator/Sensor 모두 정지 (spec QA-021)
- Visibility = Renderer.enabled — 물리/이벤트 유지 (parts-visibility spec)
- 두 도메인 의도적 차이. _partHidden dict 가 SSOT.
- Undo 시 SetActive(true) -> Unity Transform/Driver/EventBus 자동 재개
회귀 위험 없음 — Driver는 GameObject active 여부 검사 X -> 자동 재개.
중대-2 RaycastNonAlloc
`csharp
static RaycastHit[] _pickHitsBuf = new RaycastHit[64];
class RaycastHitDistanceComparer : IComparer { ... }
int hitCount = Physics.RaycastNonAlloc(ray, _pickHitsBuf, 1e5f);
System.Array.Sort(_pickHitsBuf, 0, hitCount, RaycastHitDistanceComparer.Instance);
`
- RaycastAll 매 click 시 GC alloc -> NonAlloc 정적 buffer (64 hits)
- IComparer 정적 인스턴스 (lambda alloc 회피)
- 부분 정렬 (0..hitCount만)
- 8000+ 부품 환경에서 GC spike 차단
중대-1 토스트 카운트 mismatch
ToggleVisibilityWithSelection L6858 — 토스트 _selectedParts.Count -> targets.Count로 변경. cachedTransform null 가드 통과한 실제 처리 수 표시.
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~25라인) — DeleteCommand 주석 + Raycast NonAlloc + Comparer + 토스트 fix
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.256 -> 0.1.257
검증 시나리오
치명-1 (회귀 없음 확인)
1. 부품 선택 -> Delete -> 사라짐 + Actuator 정지
2. Ctrl+Z -> 복원 + Actuator 재개
중대-2 (GC profile)
- click 100회 -> GC alloc 0 (NonAlloc 동작)
- raycast 결과 정확도 무회귀
중대-1
- 부모 선택 + 자식 hide (singleOnly) -> "1개 감춤" 정확
- 다중 선택 + 우클릭 -> targets.Count 정확
다음 사이클
- v0.1.258 — 39th stable seal 봉인 (v0.1.251~257)
- v0.1.259 — 중간-1 Color switch 캐시 + QA-040 Signal Simulator UX 분석
- v0.1.260 — QA-014 (PM 회신 받으면)
협업자 git origin/main = local. QA-014 PM 회신 계속 대기.

v0.1.256 — v0.1.256 — QA-056 hide 부품 raycast 관통

v0.1.256 v0.1.256 — QA-056 hide 부품 raycast 관통 zip release notes GitHub
협업자 PM 회신
QA-056 [P1] — hide 처리된 오브젝트 뒤 보이는 오브젝트 클릭 선택 불가. hide 부품의 Collider가 raycast를 차단.
root cause 확정
PickPartUnderMouse() L4032:
`csharp
if (Physics.Raycast(ray, out var hit, 1e5f))
{
...
if (IsPartHidden(pp)) return null; // <- 회귀 root cause
return pp;
}
`
Physics.Raycast는 가장 가까운 1 hit만 반환. hidden 부품에 hit하면 return null -> 뒤쪽 부품 도달 못 함. fallback 경로(bounds.IntersectRay)도 동일 패턴.
spec QA-056: "hide 상태에서도 컴포넌트·물리 동작 유지" (스펙 B항목) -> Collider.enabled 비활성 불가. raycast 결과 자체에서 hidden 부품을 skip해야 함.
fix — RaycastAll + sort + hidden skip
`csharp
var hits = Physics.RaycastAll(ray, 1e5f);
System.Array.Sort(hits, (a, b) => a.distance.CompareTo(b.distance));
foreach (var hit in hits)
{
var candidate = (Part 추적);
if (candidate == null) continue;
if (IsPartHidden(candidate)) continue; // hidden skip -> 다음 hit
return candidate;
}
`
fallback path도 동일 — List<(float dist, Renderer r)> 누적 + Sort + hidden skip.
영향 범위
- Collider.enabled 비활성 X — 물리/IsTrigger/이벤트 모두 유지 (spec 정합)
- 다중 hit 경우 가장 가까운 visible 부품 선택
- 모든 hit이 hidden이면 결과 null (기존과 동일)
- 성능: RaycastAll은 단일 Raycast보다 ~3-5x 느리지만 산업용 8000+ 부품에서도 ms 단위
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~40라인 -> PickPartUnderMouse 일괄 재작성)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.255 -> 0.1.256
검증 시나리오
QA-056
1. 부품 A (앞) + 부품 B (뒤) 배치 -> A를 hide
2. 씬에서 B 영역 클릭 -> B 정상 선택 (이전: A가 raycast 차단 -> null)
3. A 영역 클릭 -> null (hidden 자체 선택 X — 기존 동작)
4. 모두 hidden -> null (기존)
기존 동작 무회귀
- visible 부품만 있을 때: 가장 가까운 부품 선택 (단일 Raycast 동일)
- Gizmo 우선순위는 분기 외부에서 처리 (변경 없음)
다음 사이클
- v0.1.257 — QA-040 Signal Simulator UX 개편 spec 분석 + P1
- v0.1.258 — 39th stable seal 봉인 (v0.1.251~257)
- v0.1.259 — QA-014 Persp/Ortho (PM 회신 받으면)
협업자 git origin/main = local. QA-014 PM 회신 계속 대기.

v0.1.255 — v0.1.255 — QA-055 부품 리스트 eye click 단일 처리

v0.1.255 v0.1.255 — QA-055 부품 리스트 eye click 단일 처리 zip release notes GitHub
협업자 PM 회신
QA-055 [P1] — 부모 선택 + 자식 행 eye click -> 부모 + 자식 cascade hide 회귀.
PM 정책 (2026-05-20)
| 조작 위치 | 동작 범위 | 정책 |
|---|---|---|
| 부품 리스트 eye click | 클릭한 행만 | selection 무관 |
| 씬 우클릭 -> 감추기 | 현재 선택된 전체 | 다중 선택 반영 |
root cause 확정
ToggleVisibilityWithSelection(Part triggerPart) L6822:
`csharp
bool isMulti = _selectedParts.Count > 1 && _selectedParts.Contains(triggerPart);
`
triggerPart가 selection에 포함되면 isMulti=true -> 모든 선택 부품 처리. 부품 리스트와 씬 우클릭 호출처가 같은 함수 -> PM 정책 위반.
fix
singleOnly 파라미터 추가
`csharp
void ToggleVisibilityWithSelection(Part triggerPart, bool singleOnly = false)
{
bool isMulti = !singleOnly && _selectedParts.Count > 1 && _selectedParts.Contains(triggerPart);
...
}
`
호출처별 분기
| 호출 path | singleOnly | 동작 |
|---|---|---|
| 부품 리스트 eye click (L2947) | true | 클릭한 행만 |
| 씬 우클릭 컨텍스트 (L6766) | false (기본) | 다중 처리 |
L2947 호출:
`csharp
ToggleVisibilityWithSelection(p, singleOnly: true);
`
L6766 호출 (기존 그대로):
`csharp
ToggleVisibilityWithSelection(p);
`
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+5라인) — ToggleVisibilityWithSelection 시그니처 + L2947 호출
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.254 -> 0.1.255
검증 시나리오
QA-055
1. 부모 부품 클릭 (선택 상태) -> 자식 행 eye click -> 자식만 hide (부모 유지)
2. 자식만 선택 -> 자식 eye click -> 자식만 hide
3. 다중 선택 (부모+자식) -> 자식 eye click -> 자식만 hide (PM 정책)
기존 동작 유지
- 씬 우클릭 -> 감추기: 다중 선택 시 N개 일괄 hide (기존)
- 단일 선택 시 eye click: 클릭한 부품만 (기존)
다음 사이클
- v0.1.256 — QA-056 hide Collider raycast 차단 (별도 사이클, 회귀 위험)
- v0.1.257 — QA-040 Signal Simulator UX 개편 spec 분석
- v0.1.258 — QA-014 Persp/Ortho (PM 회신)
- v0.1.259 — 39th stable seal 봉인 (v0.1.251~258)
협업자 git origin/main = local. QA-014 PM 회신 계속 대기.

v0.1.254 — v0.1.254 — QA-054/057/058 협업자 잔존 QA 3건 일괄 fix

v0.1.254 v0.1.254 — QA-054/057/058 협업자 잔존 QA 3건 일괄 fix zip release notes GitHub
협업자 PM 회신 3건
QA-054 [P1] — 동일 오브젝트 센서 중복 부착 미차단
QA-057 [P2] — "Show Hidden" -> "Unhide All" 버튼명 변경 + 영구 해제 명시
QA-058 [P2] — Collision 결과 텍스트 개발자 용어 -> 사용자 친화
fix
QA-054 model-add-sensor 중복 차단
기존: 다중 선택 시 각 부품에 1개씩 추가하지만 이미 부착된 부품도 무차별 재추가.
`csharp
foreach (var p in _selectedParts) { if (p != null) { AddPhotoSensorToPart(p); added++; } }
`
fix: alreadySensor 가드 추가 (Add Servo/Pneumatic/Rotary 패턴 미러):
`csharp
bool alreadySensor = p.Sensors != null && p.Sensors.Count >= 1;
if (alreadySensor) { skipped++; continue; }
AddPhotoSensorToPart(p);
`
토스트:
- 다중: "Sensor 추가: {N} 부착 · {M} skip (이미 부착)"
- 단일 차단: "Add Sensor: 이미 PhotoSensor가 부착되어 있습니다"
QA-057 Show Hidden 버튼명 변경
Ribbon.uxml review-show-hidden:
- text: "Show Hidden" -> "Unhide All"
- tooltip: "모든 hide 부품 영구 해제 (탭 이탈 후에도 유지)" (PM 정책 A안 명시)
auto-revert 로직은 이미 없음 (영구 해제 동작) — 정책 변경만 반영.
QA-058 Collision 텍스트 사용자 친화
| 기존 | 신규 |
|---|---|
| 충돌: 2+ 부품 선택 필요 | 2개 이상의 부품을 선택하세요 |
| 충돌: 부품 mesh 없음 | 부품에 메시 정보가 없습니다 |
| 충돌: 0/{pairs}쌍 겹침 | 충돌 없음 (검사한 {pairs}쌍 모두 정상) |
| 충돌: {hits}/{pairs}쌍 ... | 겹치는 부품: {hits}쌍 ... |
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~12라인) — model-add-sensor 가드 + Collision 토스트
- Assets/UI/Components/Ribbon.uxml — review-show-hidden text/tooltip
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.253 -> 0.1.254
검증 시나리오
QA-054
1. 부품 선택 -> Add Sensor -> 부착 -> Add Sensor 재클릭 -> 토스트 "이미 부착되어 있습니다"
2. 3 부품 다중 선택 (1개는 이미 부착) -> Add Sensor -> "2 부착 · 1 skip"
QA-057
- Review 탭 버튼 라벨 "Unhide All" 표시
- click -> 모든 hidden 부품 해제 + 탭 이동 후 유지
QA-058
- 1 부품 선택 + Collision click -> "2개 이상의 부품을 선택하세요"
- 2 부품 (충돌 없음) -> "충돌 없음 (검사한 1쌍 모두 정상)"
- 2 부품 (충돌) -> "겹치는 부품: 1쌍 — A↔B"
다음 사이클
- v0.1.255 — QA-040 Signal Simulator UX 개편 spec 분석 + P1
- v0.1.256 — QA-055 부모 + 자식 cascade hide (parts-list-visibility spec 검토)
- v0.1.257 — QA-056 hide 오브젝트 Collider raycast 차단 (mid 회귀 위험)
- v0.1.258 — QA-014 Persp/Ortho (PM 회신 받으면)
- v0.1.259 — 39th stable seal 봉인 검토
협업자 git origin/main = local. QA-014 PM 회신 계속 대기.

v0.1.253 — v0.1.253 — QA-053 Add Rotary Inspector 카드

v0.1.253 v0.1.253 — QA-053 Add Rotary Inspector 카드 zip release notes GitHub
협업자 PM 회신
QA-053 [P1] — Add Rotary 후 프로퍼티 창에 파라미터 미표시 (v0.1.240).
root cause 확정
RenderActuatorBlock L5478~5496 에 hasServo / hasPneumatic 카드만 렌더. hasRotary 분기 누락. 주석 명시: "Rotary 카드 렌더는 별도 사이클 (있으면 추후 추가)".
v0.1.161에서 RotaryActuator 데이터 + v0.1.162에서 Driver registration 추가 — Inspector UI는 미완.
fix
1. RenderActuatorBlock 분기 추가
`csharp
else if (hasRotary)
{
for (int i = 0; i < p.RotaryActuators.Count; i++)
RenderRotaryCard(p, p.RotaryActuators[i]);
}
`
2. RenderRotaryCard 신설 (ServoAxisCard 패턴 미러)
- 헤더: ID + "[Rotary]" 표기 + 삭제 버튼
- 회전 파라미터: RPM / 정격토크 / 감속비
- 각도 기준: Home(°) / RLS(°) / FLS(°)
- 가속 프로파일: 가속(s) / 감속(s) 슬라이더
- Command 4 버튼: ◀ 역회전 / ■ 정지 / ▶ 정회전 / ⌂ Home
- Modbus 매핑: Coil Fwd/Bwd/Stop/Home + Reg Angle
- 런타임 진단: 상태(색상별) / 현재각도(°) / 각속도(°/s)
QA-053 답변 (handshake.md)
- 확인 결과: Add Rotary는 RotaryActuatorActuator 부착 (별도 컴포넌트, PneumaticCylinder Linear/Rotary 드롭다운과 별개)
- 수정 내용: RenderRotaryCard 신설 + RenderActuatorBlock 분기 추가
- 수정 빌드: v0.1.253
QA-034 답변 (handshake.md, 코드 변경 없음)
- 확인 결과: Present Tab 존재 — 리본 탭 8번째 (가장 우측)
- 탭 순서: File / Edit / View / Model / Simulation / Communication / Review / Present
- Screenshot + ▶ Scenario Play 버튼 모두 정상 (v0.1.205 P1 / v0.1.211 P2)
- 미구현 사유 X — 협업자 탭 8개 중 마지막 위치 확인 시 발견 가능
QA-040 답변 (handshake.md, 별도 사이클)
- 확인 결과: Signal Simulator UX 개편 spec 확정 (handshake.md L725~ 모니터/제어 분리)
- spec 분석 + 구현 작업량 검토 필요 -> v0.1.254+ 별도 사이클 예약
- 우선 v0.1.253은 QA-053 (정량 충격 큰 결함) 우선 처리
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+115라인) — RenderRotaryCard 신설 + 분기 추가
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.252 -> 0.1.253
검증 시나리오
1. 부품 선택 -> Model 탭 -> "Add Rotary" 클릭 -> 프로퍼티 패널에 RotaryCard 표시
2. RPM / 정격토크 / 감속비 입력 정상
3. ◀▶ 회전 명령 -> 부품 회전 + 현재각도 실시간 갱신
4. Coil 4개 + Reg Angle 입력 -> Modbus 매핑 가능
다음 사이클
- v0.1.254 — QA-040 Signal Simulator UX 개편 spec 분석 + P1 착수
- v0.1.255 — QA-014 Persp/Ortho 회귀 (PM 회신 받으면)
- v0.1.256 — 39th stable seal 봉인 (v0.1.251~255 5사이클)

v0.1.252 — v0.1.252 — DeleteCommand 다중 선택 풀 처리

v0.1.252 v0.1.252 — DeleteCommand 다중 선택 풀 처리 zip release notes GitHub
critic 중간-2 완전 fix
v0.1.250에서 정직 토스트 안내만 추가했으나, 본 사이클은 풀 처리 — DeleteCommand 자체를 List로 확장하여 다중 선택 일괄 삭제 + 일괄 Undo.
설계
단일 vs 다중 통합
DeleteCommand(Factory00Bootstrap, List) — 단일은 List.Count=1로 wrap. VisibilityCommand 미러 (List 패턴).
Execute
`csharp
foreach (var p in _targets)
{
p.cachedTransform.gameObject.SetActive(false);
_host._partHidden[p.id] = true;
}
// selection 일괄 해제
foreach (var p in _targets)
{
if (_host._selectedPart == p) _host._selectedPart = null;
_host._selectedParts.RemoveAll(x => x == p);
}
// UI 1회 갱신 (RebuildVisibleParts / Rebuild / Gizmo)
`
Undo
`csharp
foreach (var p in _targets)
{
p.cachedTransform.gameObject.SetActive(true);
_host._partHidden[p.id] = _wasHiddenBefore[p.id];
}
_host._selectedPart = _selectedBefore;
_host._selectedParts.AddRange(_selectedListBefore);
`
선택 상태 복원 완전 — _selectedPart + _selectedParts List 모두 이전 snapshot.
보존 정책 일관
DeletePart() 기존 정책 미러:
- SetActive(false) 직접 호출 — 물리·이벤트·폴링 모두 disable (visibility만 토글하는 SetPartVisible과 의도적 차이)
- _partHidden[id]=true — 트리 표시 hidden
- .glb 원본 불변 (Parts 리스트 보존)
자식 cascade 처리는 leaf-only P1 정책 일관 (어셈블리 부모 삭제 시 자식 별도 처리 필요는 v0.1.253+ BatchDelete 확장).
토스트 메시지
| 케이스 | 메시지 |
|---|---|
| 단일 | "삭제 (워크스페이스): {name}" |
| 다중 | "삭제: {N}개 일괄 (Ctrl+Z 복원)" |
| Undo 단일 | "Undo 삭제: {name}" |
| Undo 다중 | "Undo 삭제: {N}개 일괄 복원" |
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~90라인 -> DeleteCommand class 일괄 재작성 + DeleteSelectedPart 헬퍼 확장)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.251 -> 0.1.252
검증 시나리오
단일 (회귀 없음)
1. 부품 1개 선택 -> Edit Delete (또는 Delete 키) -> 사라짐
2. Ctrl+Z -> 복원
다중 (신규)
1. Ctrl+A -> 모든 부품 선택 -> Delete -> 모두 일괄 삭제 (토스트 "N개 일괄")
2. Ctrl+Z -> 모두 일괄 복원 + selection 복원
3. Shift-click 3개 선택 -> Delete -> 3개만 삭제 + 나머지 유지
4. Ctrl+Z -> 3개 복원
Description (UndoStack 표시)
- 단일: "삭제: {name}"
- 다중: "삭제: {N}개 일괄"
다음 사이클
- v0.1.253 — 협업자 잔존 QA 일괄 (QA-034 Present Tab 위치 / QA-040 Signal Simulator UX / QA-053 Add Rotary)
- v0.1.254 — QA-014 Persp/Ortho (PM 회신 받으면)

v0.1.251 — v0.1.251 — critic 보류 결함 일괄 fix

v0.1.251 v0.1.251 — critic 보류 결함 일괄 fix zip release notes GitHub
처리
| 등급 | 결함 | 처리 |
|---|---|---|
| 중대-1 | hud-root Space TrickleDown NavigationSubmit 미차단 | 주석 강화 — Blur가 실질 방어선 명시 |
| 중대-2 | sim-play simPauseBtn null 시 텍스트 무음 실패 | 주석 강화 — closure 캡처 의도 + null 영향 명시 |
| 중간-3 | BindSlider FloatField null 미포함 early return | LogWarning + 단독 동작 보장 |
| 사소-1 | _label* 필드명 (FloatField인데 prefix _label) | _value* rename (_valueMouse/Pan/Fp) |
중대-3 (QA-006 진단 로그) + 중간-2 (다중 Delete 안내) = v0.1.250 처리 완료. 중간-1 (DeleteCommand SetPartVisible 우회)는 BatchDeleteCommand 신설 시 통합 — v0.1.252 예정.
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs — Space 가드 + sim-play 주석 강화 (10라인 boost)
- Assets/Scripts/UI/SettingsPanelViewModel.cs_label* -> _value* rename + BindSlider null 가드 (12건)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.250 -> 0.1.251
검증 시나리오
- Space 가드 코드 path 무회귀 (이전 동작 그대로)
- sim-play 동작 무회귀
- 설정창 슬라이더 양방향 sync 무회귀
- (FloatField null 케이스는 정상 빌드에서 0건이라 추가 검증 X)
다음 사이클
- v0.1.252 — BatchDeleteCommand 신설 (다중 선택 Delete 풀 처리 + 중간-1 SetPartVisible 경유 통합)
- v0.1.253 — 협업자 잔존 QA 항목 (QA-034 Present Tab 위치 / QA-040 Signal Simulator UX / QA-053 Add Rotary 등)
- v0.1.254 — QA-014 (PM 회신 받으면)

v0.1.250 — v0.1.250 — critic 중대 2건 fix (38th stable seal 직전)

v0.1.250 v0.1.250 — critic 중대 2건 fix (38th stable seal 직전) zip release notes GitHub
critic 코드리뷰 결과 (v0.1.241~249)
| 등급 | 건수 | 처리 |
|---|---|---|
| 치명 | 0 | — |
| 중대 | 3 | 중대-3 fix · 중대-1/2 진단 후 보류 |
| 중간 | 3 | 중간-2 fix · 나머지 보류 |
| 사소 | 2 | 다음 사이클 |
판정: CONDITIONAL -> 본 사이클 fix 후 PASS 진입.
중대-3 fix — QA-006 진단 Debug.Log 제거
Factory00Bootstrap.cs:3203 v0.1.235 진단 Debug.Log 가 매 LMB down 마다 발화 -> v0.1.218 AC "QA 코드 빌드 제거" 직접 위반. Player.log 오염.
`csharp
// 제거됨
Debug.Log($"[QA-006 진단] LMB_DOWN pos=...");
`
QA-006 root cause는 v0.1.191 fix 완료 — 진단 로그는 잔재. 미사용 주석/코드 모두 정리.
중간-2 fix — 다중 선택 Delete 정직 안내
3개 선택 + Delete 시 첫 1개만 삭제되는 동작에 대한 사용자 mental model 차단. BatchDeleteCommand 신설은 v0.1.251 예약.
`csharp
if (_selectedParts != null && _selectedParts.Count > 1)
FlashToast($"Delete: 다중 선택 {N}개 중 첫 부품만 (다중 삭제는 v0.1.251 예정)");
`
보류 결함 (다음 사이클 예정)
중대-1 — hud-root TrickleDown Space 가드의 NavigationSubmit 경로 미차단
실질 방어선 btn.Blur() (line 1441)이 정상 동작 — 회귀 위험 낮음. 주석 보강 권장 (v0.1.251).
중대-2 — sim-play 핸들러 simPauseBtn null 시 텍스트 무음 실패
null 가드 정상 동작 + sim-pause-toggle UXML 존재 검증 완료. 코드 path는 정합. 주석 보강 권장 (v0.1.251).
중간-1 — DeleteCommand SetActive 직접 호출 (SetPartVisible 우회)
DeletePart() 기존 패턴 미러. 어셈블리 자식 cascade는 leaf-only P1 정책 일관. v0.1.252 BatchDeleteCommand 신설 시 SetPartVisible 경유로 통합 권장.
중간-3 — BindSlider FloatField null 미포함 early return
초기 sync 부분 작동 + 디버깅 시간 경미. 사소 보강.
사소-1 — _labelMouse/_labelPan/_labelFp 필드명 잔존
타입 FloatField인데 prefix는 _label. 다음 사이클 rename 권장.
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~10라인) — QA-006 진단 제거 + 다중 선택 토스트
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.249 -> 0.1.250
38th stable seal 진입 조건
- [완료] critic 중대-3 fix (QA-006 진단 잔재 제거)
- [완료] critic 중간-2 fix (다중 Delete 안내)
- [완료] 9 사이클 누적 변경 (v0.1.241~249) — 협업자 PM 회신 7건 + critic 자체 검토 통과
- 다음: stable seal release notes + INDEX 갱신 + handshake.md 답변 기입
다음 사이클
- v0.1.251 — 38th stable seal 봉인 (release notes / 영구 보존 zip / INDEX / handshake)
- v0.1.252 — 중대-1/2 주석 보강 + 사소-1 rename + BatchDeleteCommand 신설 (중간-1 통합)
- v0.1.253 — QA-014 Persp/Ortho (PM 회신 받으면)
협업자 git origin/main = local. QA-014 PM 회신 계속 대기.

v0.1.249 — v0.1.249 — QA-009 hud-root Space 가드 확장

v0.1.249 v0.1.249 — QA-009 hud-root Space 가드 확장 zip release notes GitHub
협업자 PM 회신
QA-009 [P0] — 좌측 패널 내부창 전체 공백 (간헐). v0.1.240 재발 확인 (2026-05-20).
PM 보고: Space 키 트리거 + F11 복구. 가설: UI Button focus 보유 시 Space=click 발화.
v0.1.244 fix 한계 진단
v0.1.244에서 ribbon 한정 KeyDown Space 가드 + Click 후 Blur. PM은 v0.1.240 기준 검증 -> v0.1.244 fix 후 재검증 없음.
추가 잔존 가능성:
- 좌측 패널 안 햄버거 ≡ 외 버튼 (검색 X clear / 부품 트리 row Activate 등)이 Ribbon 외부 -> v0.1.244 가드 미적용
- 부품 트리 ListView focus + Space -> row activate -> 패널 hiding 가능성
v0.1.249 fix — hud-root 전체 확장
`csharp
var hudRootKey = root.Q("hud-root") ?? root;
hudRootKey.RegisterCallback(evt => {
if (evt.keyCode == KeyCode.Space && evt.target is Button) {
evt.StopPropagation();
evt.PreventDefault();
}
}, TrickleDown.TrickleDown);
foreach (var btn in hudRootKey.Query
btn.clicked += () => btn.Blur();
`
- TrickleDown으로 Button focus 보유 시 Space click 발화 차단
- evt.target Button 한정 — ContextMenu Enter activate 등 다른 키 영향 없음
- 모든 Button click 후 Blur — focus 누적 차단
- Space=카메라 상승키는 Input.GetKey 폴링 (별도 path) — 영향 0
영향 범위
- Ribbon Button (이미 v0.1.244 처리) — 동등 효과로 통합
- 좌측 패널 ≡ 햄버거·검색 X·동작 버튼·Inspector edit 버튼 등 모든 Button cascade
- ListView row Activate (Space) 영향 없음 (target이 ListView, Button 아님)
- ContextMenu Enter activate 영향 없음 (KeyCode.Enter는 가드 외)
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~12라인 -> 확장된 ~20라인) — ribbon -> hud-root 확장
- ProjectSettings/ProjectSettings.asset (0.1.248 -> 0.1.249)
검증 시나리오
1. 좌측 패널 ≡ click -> 패널 펼침 -> Space -> 패널 그대로 (이전: 접힘 회귀 가능)
2. 부품 트리 row click -> Space (카메라 상승) -> 패널 변화 0 + 카메라 상승 정상
3. Inspector 버튼 click -> Space -> 버튼 재발화 0
다음 사이클
- v0.1.250 — 38th stable seal 봉인 검토 (v0.1.241~249 9 사이클)
- v0.1.251 — QA-014 Persp/Ortho 회귀 (PM 회신 받으면)
- v0.1.252 — QA-040 Signal Simulator UX 개편 (스펙 확정)
협업자 git origin/main = local. QA-014 PM 회신 계속 대기.

v0.1.248 — v0.1.248 — QA-033/035 Simulation Play 버튼 + 자동 시작 차단

v0.1.248 v0.1.248 — QA-033/035 Simulation Play 버튼 + 자동 시작 차단 zip release notes GitHub
협업자 PM 회신 2건 일괄 (동일 빌드 권장)
QA-033 [P1] — Simulation Tab Play 버튼 누락
QA-035 [P0] — Play Mode 진입 시 Scenario Play 자동 시작 (PM QC 블로커)
QA-033/035 root cause 확정
현재 Simulation Tab 버튼: Signal Simulator | Interface Emulation | Pause | Stop
Play 버튼 없음 -> 협업자가 "Interface Emulation" 을 Play 진입점으로 오인 click -> RunInterfaceEmulationDemo 코루틴 발화 -> Phase A 부품 자동 어셈블리(컴포넌트 자동 추가 + 자동 이동) -> 협업자가 "Scenario Play 자동 시작" 으로 보고.
코드 grep 결과 SimulationPlayStartedEvent -> RunInterfaceEmulationDemo 자동 호출 path 0건. F12 키 / sim-interface-emulation 버튼 / present-scenario-play 버튼 (Present Tab) 3개 진입점만 존재 — 모두 명시 사용자 액션.
fix
1. Simulation Tab Play 버튼 신설 (Ribbon.uxml)
`xml
tooltip="시뮬레이션 시작 (Time.timeScale=1 보장). Interface Emulation·Scenario Play와 독립."/>
`
위치: Signal Simulator 좌측 (시작 진입점이므로 leftmost).
2. sim-play 핸들러 (Factory00Bootstrap.cs)
`csharp
simPlayBtn.clicked += () => {
Time.timeScale = 1f;
if (simPauseBtn != null) simPauseBtn.text = "Pause";
FlashToast("시뮬레이션 시작 (Time.timeScale=1)");
};
`
- Pause 상태 해제 -> 시뮬레이션 활성
- Interface Emulation 자동 호출 X (별도 버튼 유지)
- Scenario Play (Present Tab) 자동 호출 X
- 사이드 이펙트 0건
3. sim-interface-emulation tooltip 정정
`
F12 인터페이스 에뮬레이션 데모 시퀀스 실행 (수동 클릭만 — 자동 시작 X)
`
협업자 보고 root cause 메모: Play 부재로 인한 오인 -> 명시 추가.
영향 범위
- Simulation Tab 버튼 5개 (Play 추가): Play | Signal Simulator | Interface Emulation | Pause | Stop
- Play state machine은 v0.1.249+에서 enable/disable 정교화 (현재 모두 활성 — Play timeScale=1 / Pause 0/1 / Stop CommandHome 각자 독립 동작)
변경 파일
- Assets/UI/Components/Ribbon.uxml — sim-play 버튼 추가 + tooltip 정정
- Assets/Scripts/Game/Factory00Bootstrap.cs — sim-play 핸들러 (+10라인)
- ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.247 -> 0.1.248
검증 시나리오
QA-033
1. Ribbon -> Simulation 탭 -> Play 버튼 시각 존재 확인
2. Play click -> timeScale=1 토스트 출력
3. Pause click 후 Play click -> Resume -> Pause 복귀 (timeScale=1)
QA-035
1. Play click -> Scenario Play 자동 시작 0 (Interface Emulation 코루틴 미발화)
2. sim-interface-emulation click -> 명시 데모만 시작
3. present-scenario-play click -> 명시 Scenario Play만 시작
다음 사이클
- v0.1.249 — Play state machine 정교화 (Idle/Playing/Paused 별 enabled state)
- v0.1.250 — QA-009 좌측 패널 내부창 간헐 공백 진단
- v0.1.251 — QA-014 Persp/Ortho 회귀 (PM 회신 받으면)
협업자 git origin/main = local. QA-014 PM 회신 계속 대기.

v0.1.247 — v0.1.247 — QA-007/052 splitter·스크롤바 드래그 누수 fix

v0.1.247 v0.1.247 — QA-007/052 splitter·스크롤바 드래그 누수 fix zip release notes GitHub
협업자 PM 회신 2건 root cause 동일
QA-007 [P1] — splitter 빠른 드래그 시 씬 드래그 누수 + 감도 슬라이더 3종 동일 (좌측 패널 splitter / 마우스회전 / MMB 패닝 / 1인칭 시선)
QA-052 [P1] — 프로퍼티 패널 스크롤바 드래그 시 Transform Gizmo 이벤트 누수
PM 추정 동일 루트 — StopPropagation() 미적용. 실제 root cause는 다름
root cause 확정
Bootstrap Update L3236 — 단순 click 분기에 overUIAtDown 가드 누락
`csharp
// 기존 (v0.1.246)
bool overUI = IsPointerOverUI(Input.mousePosition); // UP 시점
if (inViewport && !overUI && !overGizmo && _cursorMode == CursorMode.Select
&& (Time.frameCount - _lmbDownFrame) < 30 && (Input.mousePosition - _lmbDownPos).magnitude < 5f)
{
var picked = PickPartUnderMouse(); // <- UI drag 누수
...
}
`
빠른 splitter/스크롤바 drag 패턴:
1. DOWN — splitter / 스크롤바 위 (UI element)
2. 빠르게 drag -> 마우스가 viewport 영역으로 빠짐
3. UP — viewport 위치. IsPointerOverUI(UP) = false
4. 거리 5px 미만 + 30 frame 이내 -> click 판정 -> PickPartUnderMouse -> 부품/Gizmo 선택 변경
drag-select 분기 (L3211)는 이미 overUIAtDown 가드 있어 차단됨. 단순 click 분기만 가드 누락.
fix
`csharp
// v0.1.247
bool overUI = IsPointerOverUI(Input.mousePosition); // UP 시점
bool overUIAtDown = IsPointerOverUI(_lmbDownPos); // DOWN 시점 (추가)
if (inViewport && !overUI && !overUIAtDown && !overGizmo && _cursorMode == CursorMode.Select
&& ... )
{
PickPartUnderMouse();
}
`
DOWN 시점 UI 위였으면 마우스 down 자체가 UI element 상호작용 -> 씬 click 판정 0.
영향 범위 (단일 가드 추가로 4건 cascade 차단)
| QA | 시나리오 | 차단 |
|----|----------|------|
| QA-007 | 좌측 패널 splitter 빠른 drag | [완료] |
| QA-007 확장 | 감도 슬라이더 3종 (마우스/MMB/1인칭) | [완료] |
| QA-052 | 프로퍼티 스크롤바 click -> Transform Gizmo | [완료] |
| QA-009/031 잔존분 | UI 위 5px 미만 drag -> 부품 선택 | [완료] |
StopPropagation() 추가 필요 X — Input.GetMouseButton 폴링은 PointerEvent system과 별개로 동작하므로 overUIAtDown 단일 가드로 충분.
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+5라인) — overUIAtDown 가드 추가
- ProjectSettings/ProjectSettings.asset (bundleVersion 0.1.246 -> 0.1.247)
검증 시나리오
QA-007 splitter
1. 좌측 패널 splitter 빠른 drag (수십 px) -> 씬 부품 선택 변경 0
2. 감도 슬라이더 핸들 빠른 drag -> 씬 선택 0
3. 마우스 천천히 drag (정상 케이스) -> 회귀 없음
QA-052 스크롤바
1. 프로퍼티 패널 스크롤바 click -> Transform Gizmo 이동 0
2. 스크롤바 drag -> 오브젝트 위치 변경 0
다음 사이클
- v0.1.248 — QA-035 Play Mode 진입 시 Scenario Play 자동 시작 fix
- v0.1.249 — QA-033 Simulation Tab Play 버튼 누락
- v0.1.250 — QA-009 좌측 패널 내부창 간헐 공백 진단
협업자 git 신규 commit 없음 (origin/main = local). QA-014 회신 계속 대기.

v0.1.246 — v0.1.246 — QA-047 Delete Undo + QA-041 설정창 수치 필드 입력

v0.1.246 v0.1.246 — QA-047 Delete Undo + QA-041 설정창 수치 필드 입력 zip release notes GitHub
협업자 PM 회신 2건 fix
QA-047 [P0] 높음 — Delete Undo(Ctrl+Z) 미동작
QA-041 [P1] spot-check 탈락 — 설정창 감도 슬라이더 수치 필드 편집 불가
QA-047 root cause 확정
editDeleteBtn.clicked += () => DeletePart(...) 직접 호출 -> UndoStack 미경유 -> Ctrl+Z 무동작.
Delete 키 (Update L3437) 도 동일 패턴.
QA-047 fix
1. DeleteSelectedPart() 헬퍼 신설
DuplicateSelectedPart 옆 패턴 미러. selection 없으면 토스트 + return.
2. DeleteCommand IEditCommand 신설
VisibilityCommand 옆 패턴 미러:
- Execute: GameObject.SetActive(false) + _partHidden[id]=true + selection 해제 + UI 갱신
- Undo: GameObject.SetActive(true) + _partHidden 복원 + selection 복원 + UI 갱신
- DeletePart() 보존 정책과 동일 (.glb 원본 불변, Parts 리스트 유지)
3. 호출처 교체 (2건)
- editDeleteBtn.clicked += DeletePart(...) -> += DeleteSelectedPart()
- Input.GetKeyDown(KeyCode.Delete) 분기 -> DeleteSelectedPart()
QA-041 root cause 확정
— Label은 read-only 위젯. 사용자가 우측 "수치 필드 클릭·입력" 시도하지만 입력 받지 못함.
QA-036/037 (RenderInspector 주기 Clear)과 다른 원인 — PM 메모 "동일 루트" 가정 정정.
QA-041 fix
1. UXML Label -> FloatField (3건)
-> . label-pan-sens / label-fp-sens 동일.
2. SettingsPanelViewModel.cs BindSlider 양방향 sync
Label _labelMouse, _labelPan, _labelFp -> FloatField. BindSlider 시그니처 변경.
- Slider 드래그 -> f.SetValueWithoutNotify(round 0.1) (no callback echo)
- FloatField 직접 입력 -> Mathf.Clamp(low~high) + s.SetValueWithoutNotify + setter
3. USS .c-settings__numfield 추가
width 60px + 좌측 6px margin. 시각 일관성.
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+85라인) — DeleteCommand class + DeleteSelectedPart 헬퍼
- Assets/Scripts/UI/SettingsPanelViewModel.cs (~15라인) — FloatField 타입 + 양방향 sync
- Assets/UI/MainHUD.uxml (3 element 타입 변경)
- Assets/UI/Theme/components.uss (+7라인 .c-settings__numfield)
- ProjectSettings/ProjectSettings.asset (bundleVersion 0.1.245 -> 0.1.246)
검증 시나리오
QA-047
1. 부품 선택 -> Edit Delete (또는 Delete 키) -> 부품 사라짐
2. Ctrl+Z -> 부품 복원 + selection 복원 + Inspector 재표시
3. Ctrl+Y (또는 다시 Ctrl+Z 후) -> 다시 삭제
QA-041
1. 설정창 열기 -> 마우스 회전 감도 슬라이더 드래그 -> 우측 수치 필드 실시간 갱신
2. 우측 수치 필드 클릭 -> 키보드 입력 -> 슬라이더 동기화
3. 범위 외 값 입력 (예: 100) -> low/high clamp 자동 적용
4. 패닝 감도 / 1인칭 감도 동일 동작
다음 사이클
- v0.1.247 — QA-014 Persp/Ortho v0.1.240 퇴행 (PM 회신 받으면)
- v0.1.248 — QA-007 splitter 드래그 시 씬 드래그 누수 (감도 슬라이더 3종 포함)
- v0.1.249 — QA-033/035 Simulation Inspector 진입 차단

v0.1.245 — v0.1.245 — QA-036/037 프로퍼티 패널 드롭다운/입력 fix

v0.1.245 v0.1.245 — QA-036/037 프로퍼티 패널 드롭다운/입력 fix zip release notes GitHub
협업자 PM 보고
QA-036: ActuatorType 드롭다운 클릭 시 즉시 닫힘 (메뉴 항목 선택 불가)
QA-037: 서보축 컴포넌트 HomePosition / MaxPosition / MaxVelocity 등 수치 입력 필드 입력 불가
PM 메모: "QA-036+QA-037+QA-041은 동일 루트 원인 추정 — 일괄 수정 권장"
root cause 확정
RenderInspector가 0.25초 주기로 자동 호출 + _detailPane.Clear()
Bootstrap line 836: const float DRAWER_REFRESH_INTERVAL = 0.25f;
Bootstrap line 838 기존 주석: "Update() L2120 가 0.25s 마다 RenderInspector -> _detailPane.Clear() -> axisGroup destroy -> 새 closure"
증상 분석:
- 사용자가 TextField 클릭 + 입력 시작 -> 0.25s 후 RenderInspector -> Clear -> TextField destroy -> 새 TextField 생성 -> 사용자 입력 무효
- 사용자가 DropdownField 클릭 -> popup 열림 -> 0.25s 후 Clear -> DropdownField destroy -> popup도 destroy -> "즉시 닫힘"
fix
1. `IsInspectorEditFocused()` 헬퍼 신설
`csharp
bool IsInspectorEditFocused() {
if (_detailPane == null || uiDocument == null) return false;
var focused = uiDocument.rootVisualElement?.focusController?.focusedElement as VisualElement;
if (focused == null) return false;
// _detailPane의 자손인지 ancestor 추적
var cur = focused;
while (cur != null) {
if (cur == _detailPane) return true;
cur = cur.parent;
}
return false;
}
`
기존 IsAnyTextFieldFocused는 root.focusedElement가 TextField인지만 체크. DropdownField / Toggle / Slider / NavigatedListView 등 미포함 + detail-pane 외부 TextField도 미구분 -> 본 헬퍼는 _detailPane 자손 한정.
2. 주기 RenderInspector 가드 (line 3595)
`csharp
// 이전: !_inspectorDragLock 만
if (_selectedPart != null && _detailPane != null && !_inspectorDragLock)
// 신규: !IsInspectorEditFocused() 추가
if (_selectedPart != null && _detailPane != null && !_inspectorDragLock && !IsInspectorEditFocused())
`
영향 범위
- TextField (HomePosition / MaxVelocity / 모든 수치 입력) [OK]
- DropdownField (ActuatorType / 좌표계 / 메이커 프리셋 / 해상도 등) [OK]
- Toggle (Lit / 로컬 회전 등) [OK] — focus 보유 시 외부 click 전까지 유지
- Slider — 일반적으로 focus 유지 X (drag 후 자동 해제), 안전망
부가 효과
- QA-041 설정창 수치 필드 — settings-panel은 _detailPane 외부 -> 별도 fix 필요. 다음 사이클.
- 0.25s 주기 RenderInspector가 외부 click 또는 ESC로 포커스 해제 시 다음 tick에 즉시 재개 -> 사용자 입력 종료 후 inspector 갱신 자동.
검증 시나리오 (PM checklist QA-011)
1. 부품 선택 -> 서보축 부착 -> 프로퍼티 패널의 HomePosition TextField 클릭 -> 값 입력 -> 정상 (이전: 입력 불가)
2. 부품 선택 -> 서보축 부착 -> ActuatorType 드롭다운 클릭 -> popup 메뉴 유지 -> 항목 선택 가능 (이전: 즉시 닫힘)
3. 외부 click 또는 ESC -> 다음 0.25s tick에 RenderInspector 자동 재개 -> 갱신 값 반영
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+25라인)
- IsInspectorEditFocused() 신설 (line 414 부근, IsAnyTextFieldFocused 옆)
- 주기 RenderInspector 가드 (line 3595)
다음 사이클
- v0.1.246 — QA-041 설정창 수치 필드 + QA-047 Delete Undo 일괄
- v0.1.247 — QA-014 Persp/Ortho v0.1.240 퇴행
- v0.1.248 — QA-007/052 splitter/스크롤바 누수
- v0.1.249+ — QA-006 씬 클릭 간헐 + QA-033/035 Simulation

v0.1.244 — v0.1.244 — QA-009 Space 패널 접힘 + QA-031 Ctrl 카메라 충돌 fix

v0.1.244 v0.1.244 — QA-009 Space 패널 접힘 + QA-031 Ctrl 카메라 충돌 fix zip release notes GitHub
협업자 PM 일괄 점검 요청 (handshake.md 2026-05-20)
PM 명시 동일 패턴의 UI 이벤트 전파 누수 다수 발견. 일괄 fix 권장.
| QA | 현상 | 본 사이클 fix |
|---|---|---|
| QA-009 | 스페이스바 입력 시 패널 접힘 | [완료] Ribbon Button focus 해제 + Space 가드 |
| QA-031 | Ctrl+D/A 시 카메라도 이동 | [완료] WASD 카메라 Ctrl/Alt 수식키 가드 |
| QA-008 | 휠 누수 (v0.1.235 이미 fix) | 그대로 |
| QA-007 | splitter 드래그 누수 | 별도 사이클 (슬라이더 3종 일괄) |
| QA-052 | 프로퍼티 스크롤바 Gizmo 누수 | 별도 사이클 |
QA-009 fix — Ribbon Button Space 키 차단
PM 회신 (QA-023): "트리거 = 스페이스바". root cause:
- toggle-left Button click 후 Unity UI Toolkit 기본 동작 = 버튼 포커스 유지
- 그 다음 Space 키 누르면 포커스된 버튼의 click 발화 -> ToggleCollapse() 재호출 -> 패널 접힘
fix: SetupRibbonShell 안:
1. ribbon 컨테이너 KeyDownEvent 가드 — Space 키 StopPropagation + PreventDefault
2. 모든 Ribbon Button click 후 Blur() — 포커스 해제 (다음 Space가 click 트리거 못 함)
`csharp
var ribbonRoot = root.Q("ribbon");
ribbonRoot.RegisterCallback(evt => {
if (evt.keyCode == KeyCode.Space) {
evt.StopPropagation();
evt.PreventDefault();
}
}, TrickleDown.TrickleDown);
foreach (var btn in ribbonRoot.Query
var bb = btn;
bb.clicked += () => bb.Blur();
}
`
영향 범위: Ribbon 안 모든 버튼 (8 탭 헤더 + 45 명령 버튼 + 우측 위젯). Space 키로 버튼 활성화 차단.
QA-031 fix — WASD 카메라 Ctrl/Alt 수식키 가드
PM 보고: "Ctrl+D/A 시 카메라도 이동" — Ctrl+D (Duplicate) / Ctrl+A (Select All) 누를 때 카메라 WASD D/A도 처리.
fix: CameraViewController.cs Update WASD 분기에 Ctrl/Alt 가드 추가.
`csharp
bool ctrlDown = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
bool altDown = Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt);
if (!textFocused && !ctrlDown && !altDown) {
// WASD 이동 ...
}
`
영향: Ctrl/Alt 수식키 조합 누를 때 카메라 이동 비활성 -> 단축키 (Ctrl+D/A/Z/Y) 우선.
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+22라인)
- SetupRibbonShell 안 Ribbon 컨테이너 Space 가드 + 모든 Button Blur (line 1397 부근)
- Assets/Scripts/Game/CameraViewController.cs (+4라인)
- UpdateCamera WASD 분기 Ctrl/Alt 가드 (line 380 부근)
검증 시나리오 (PM checklist)
1. QA-009: ≡ 클릭 -> 패널 접힘 -> Space 키 -> 패널 그대로 (이전: 패널 다시 접힘)
2. QA-031: 부품 선택 -> Ctrl+D (Duplicate) 누름 -> 복제 동작 + 카메라 D 이동 X (이전: 카메라도 오른쪽 이동)
다음 사이클
- v0.1.245 — QA-036/037 프로퍼티 드롭다운/입력 fix
- v0.1.246 — QA-014 Persp/Ortho v0.1.240 퇴행 추적
- v0.1.247 — QA-007/052 splitter/스크롤바 일괄 (드래그 누수)
- v0.1.248 — QA-006 씬 클릭 간헐 재발 추적

v0.1.243 — v0.1.243 — QA-021 Edit Duplicate 정책 정정 (v0.1.237/238 수정)

v0.1.243 v0.1.243 — QA-021 Edit Duplicate 정책 정정 (v0.1.237/238 수정) zip release notes GitHub
협업자 PM 회신 (QA-021, 2026-05-20)
QA-013 (2026-05-17 확정) -> QA-021 변경. v0.1.237/238 구현이 구 정책 기준.
| 항목 | QA-013 (이전) | QA-021 (변경) |
|---|---|---|
| ① 메시 | Instance 참조 | Instance 참조 (유지) |
| ② 머티리얼 | 공유 | 독립 복사 (Material.Instantiate) [OK] |
| ③ ISensor/IActuator | 제외 (복제 안 함) | 함께 복제 + PLC IO 초기화 [OK] |
| ④ 자식 재귀 | 자식 Part 포함 | 자식 Part 포함 (유지) |
② 머티리얼 독립 복사 — 신규
기존 sharedMaterials 공유 -> 런타임 Emission/색상 변경 시 원본+복제본 동시 변경 -> 시뮬레이션 혼선.
`csharp
static void DuplicateMaterials(GameObject root) {
foreach (var rend in root.GetComponentsInChildren(true)) {
var src = rend.sharedMaterials;
if (src == null || src.Length == 0) continue;
var newMats = new Material[src.Length];
for (int i = 0; i < src.Length; i++)
newMats[i] = src[i] != null ? Object.Instantiate(src[i]) : null;
rend.sharedMaterials = newMats;
}
}
`
③ 컴포넌트 함께 복제 + Modbus 초기화 — 정책 반전
기존: RemoveRuntimeComponents() 호출하여 모든 MonoBehaviour Destroy
변경: deep copy (JsonUtility.FromJson + ToJson) + 물리 파라미터 유지 + Modbus 매핑 초기화
`csharp
static List DuplicateSensors(List<...> src) {
var dst = new List<...>();
foreach (var s in src) {
var copy = JsonUtility.FromJson<...>(JsonUtility.ToJson(s));
ResetSensorPlcBinding(copy);
dst.Add(copy);
}
return dst;
}
`
4 헬퍼: DuplicateSensors / DuplicateServoActuators / DuplicateRotaryActuators / DuplicatePneumaticActuators.
Modbus 매핑 초기화 효과
factory00 구조 특수성: ModbusAddressMap이 별도 dict이름 -> 주소 매핑.
복제된 component의 새 id 기반 이름은 ModbusAddressMap dict에서 자연 미매칭 -> "초기화" 효과 동등.
향후 component에 직접 Modbus 필드 추가 시 ResetSensorPlcBinding / ResetActuatorPlcBinding에 reset 로직 추가.
④ 자식 재귀 — P1 leaf-only 유지 (v0.1.238 critic 가드)
협업자 QA-021은 "자식 Part 포함 전체 복제" 명시. 그러나 factory00 P1은 leaf-only로 유지 (critic 치명 #1 회피).
자식 Part 재귀 등록은 P2 별도 사이클 예약 — 사용자 합의 받은 후 진행.
신규 헬퍼 (Bootstrap)
RegisterDuplicatedComponents(Part dup) — DuplicateCommand에서 호출.
- Sensors -> _sensorDriver.RegisterSensor
- Actuators / Rotary / Pneumatic -> _actuatorDriver.RegisterActuator
RemoveRuntimeComponents -> DEAD 이름 변경
호출처 0건. 정책 변경으로 무용지물. RemoveRuntimeComponents_DEAD 이름으로 보존 (다음 사이클에서 제거).
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+~100라인)
- DuplicateCommand.Execute: RemoveRuntimeComponents 호출 제거, DuplicateMaterials + 4 헬퍼 호출
- DuplicateMaterials (static, ~15라인)
- DuplicateSensors / Servo / Rotary / Pneumatic 4 헬퍼 (~50라인)
- ResetSensorPlcBinding / ResetActuatorPlcBinding 2 헬퍼 (현재 빈 구현)
- Bootstrap RegisterDuplicatedComponents(Part dup) 신규 internal 헬퍼
검증 시나리오 (PM checklist QA-021)
1. 부품 1개에 Servo + Sensor 부착 + Modbus 주소 매핑 후 Duplicate
2. 확인 1: 복제본에 Servo + Sensor 모두 부착됨 [OK] (이전: 제거됨)
3. 확인 2: 복제본 Modbus 매핑 비어있음 [OK] (이름 변경으로 자동 분리)
4. 확인 3: 원본 머티리얼 Emission 변경 -> 복제본 영향 X [OK] (sharedMaterials 분리)
5. 확인 4: 물리 파라미터 (속도/스트로크/감지범위) 유지 [OK]
다음 사이클
- QA-007/008/009/031/052 UI 이벤트 전파 일괄 (v0.1.244)
- QA-036/037 프로퍼티 패널 입력 fix
- QA-014 Persp/Ortho 퇴행 추적
- QA-019 P1.2 Vacuum Inspector UI

v0.1.242 — v0.1.242 — QA-044 Recent/Open 세션 1회 무력화 진단 + 안전망

v0.1.242 v0.1.242 — QA-044 Recent/Open 세션 1회 무력화 진단 + 안전망 zip release notes GitHub
협업자 PM 보고
QA-044: [P0] 최우선. Open/Recent 세션당 단 1회 동작 후 무력화. 재현 100%.
가설별 진단 로그 추가
| 가설 | 진단 로그 패턴 |
|---|---|
| 1. silent throw (Parts.ToDictionary id 중복 등) | [QA-044 진단] ApplyTwnPayload FAIL: ArgumentException |
| 2. NativeFileDialog 모달 미표시 | cmd-open NativeFileDialog return path='NULL/취소' 매번 |
| 3. _currentTwnPath stuck (null byte 등) | cmd-open click _currentTwnPath='...' 첫/두번째 비교 |
| 4. 핸들러 자체 발화 안 됨 | cmd-open click 로그 부재 |
fix (즉시 가능 부분)
1. ApplyTwnPayload 전체 try-catch + 진단 로그
기존: silent fail -> 2회 후 무력화 패턴
신규: ApplyTwnPayload (외부) + ApplyTwnPayloadCore (내부) 분리. 외부에서 전체 catch.
`csharp
void ApplyTwnPayload(payload) {
Debug.Log("[QA-044 진단] ENTRY parts=N");
try { ApplyTwnPayloadCore(payload); Debug.Log("EXIT OK"); }
catch (Exception ex) {
Debug.LogError("[QA-044 진단] FAIL: ...");
FlashToast("Open 실패 (내부 오류): ...");
}
}
`
2. Parts.ToDictionary id 중복 가드
기존: Parts.ToDictionary(p => p.id) — 중복 시 ArgumentException -> silent
신규: 명시적 dict 빌드 + 중복 skip + 로그
`csharp
var byId = new Dictionary(Parts.Count);
foreach (var p in Parts) {
if (string.IsNullOrEmpty(p.id) || byId.ContainsKey(p.id)) { dupSkipped++; continue; }
byId[p.id] = p;
}
`
가능 원인: Edit Duplicate (QA-015) 또는 LoadProject 회귀로 id 중복 생성.
3. cmd-open click 진단 로그
- cmd-open click _currentTwnPath='{...}' — _currentTwnPath stuck 추적
- cmd-open NativeFileDialog return path='...' — 다이얼로그 반환값 추적
PM 회신 요청
협업자가 v0.1.242 zip 받아 2회차 Open 시도:
1. Console / Player.log에 [QA-044 진단] 라인 캡처
2. 결과 패턴:
- ENTRY -> FAIL = 내부 throw -> fix 가능
- cmd-open click 로그 부재 = 핸들러 자체 unsubscribe (드물지만 가능)
- NativeFileDialog return path='NULL/취소' = 다이얼로그 자체 미표시 (Win32 P/Invoke issue)
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+30라인)
- ApplyTwnPayload 외부 try-catch wrapper (10라인)
- ApplyTwnPayloadCore 신설 (기존 본체 분리)
- Parts dict 중복 가드 (10라인)
- cmd-open 진단 로그 2개 (2라인)
다음 사이클
- 협업자 진단 회신 후 root cause 확정 -> v0.1.243+ fix
- 병행: v0.1.243 QA-021 Edit Duplicate 정책 정정

v0.1.241 — v0.1.241 — QA-051 .twn Open ClearScene 누락 fix

v0.1.241 v0.1.241 — QA-051 .twn Open ClearScene 누락 fix zip release notes GitHub
협업자 PM 명시 root cause (handshake.md QA-051)
"Open이 씬 교체가 아닌 컴포넌트 추가 스폰 — Transform 미복원 + New 미정리"
- ProjectLoader.Load()가 씬 초기화 없이 컴포넌트만 추가 스폰
- 프로젝트 저장·열기 기능 실질적 무효화 ([P0] 최우선)
root cause 분석
ApplyTwnPayload (Bootstrap.cs:2323):
- byId.TryGetValue(p.id, ...) 매칭만 — payload.parts에 있는 부품만 처리
- Sensors / Actuators / RotaryActuators / PneumaticActuators는 Clear + re-add
- Vacuum 3종 (v0.1.239 신규) — Clear 누락 [X]
- Transform 복원 (position / rotation / scale) — 누락 [X]
- payload에 없는 기존 부품의 컴포넌트 — 잔존 [X]
BindRibbonFileNewCommand (Bootstrap.cs:1952):
- Sensors / Actuators / RotaryActuators만 Clear
- Pneumatic / Vacuum 3종 누락 [X]
fix
신규 헬퍼 `ClearAllRuntimeComponents()` (line 2323~)
7 컴포넌트 타입 일괄 Driver Unregister + 리스트 Clear:
- Sensors (PhotoSensorComponent)
- Actuators (ServoAxisActuator)
- RotaryActuators
- PneumaticActuators
- VacuumEjectors (v0.1.239 신규 — 기존 누락)
- VacuumUnits (v0.1.239 신규 — 기존 누락 + Uninitialize() 자동 호출 via UnregisterActuator)
- AirBlowers (v0.1.239 신규 — 기존 누락)
`ApplyTwnPayload` 진입 시 호출
`csharp
ClearAllRuntimeComponents(); // 신규
var byId = Parts.ToDictionary(p => p.id);
foreach (var p in pf.parts) {
if (byId.TryGetValue(p.id, out var existing)) {
// ... 기존 컴포넌트 추가 로직
// v0.1.241 신규: Transform 복원
existing.cachedTransform.localPosition = p.position;
existing.cachedTransform.localEulerAngles = p.rotation;
existing.cachedTransform.localScale = p.scale;
existing.position = p.position;
existing.rotation = p.rotation;
existing.scale = p.scale;
}
}
`
`BindRibbonFileNewCommand` 통일
기존 inline foreach (~20라인) -> ClearAllRuntimeComponents() 호출로 단순화. Vacuum 누락 자동 fix.
검증 시나리오 (PM checklist)
1. 부품 1개에 Servo + 진공 Ejector 부착 -> Save .twn
2. 부품 위치/회전 변경 -> Save .twn (덮어쓰기)
3. 다른 .twn Open -> Servo만 1개 부착된 다른 상태
4. 검증: payload .twn의 컴포넌트 / Transform이 정확히 복원되어야
- 이전 (v0.1.240): Vacuum Ejector 잔존 + 위치 미복원
- 신규 (v0.1.241): Vacuum 정리 + 위치 복원
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+50라인)
- ClearAllRuntimeComponents() 신규 헬퍼 (50라인)
- ApplyTwnPayload 시작에 호출 추가 (1라인)
- ApplyTwnPayload Transform 복원 분기 (7라인)
- BindRibbonFileNewCommand 통일 (~20라인 -> 1라인)
다음 사이클
- v0.1.242 — QA-044 Recent/Open 세션 1회 무력화 추적
- v0.1.243 — QA-021 Edit Duplicate 정책 정정 (머티리얼 독립 + 컴포넌트 포함)

v0.1.240 — v0.1.240 — Vacuum critic CONDITIONAL fix (치명 1 + 중대 2 + 중간 1 + 사소 처리)

v0.1.240 v0.1.240 — Vacuum critic CONDITIONAL fix (치명 1 + 중대 2 + 중간 1 + 사소 처리) zip release notes GitHub
critic v0.1.239 판정: CONDITIONAL -> v0.1.240 fix
| 등급 | 발견 | 처리 |
|---|---|---|
| 치명 | 1 (VacuumUnit unsubscribe 누락) | 본 사이클 fix |
| 중대 | 3 (_sceneRoot / CaptureDistanceMm / UpdateActuator) | 2 fix + 1 P1.2 예약 |
| 중간 | 3 (CommandBackward 사이드이펙트 / 파일 분리 / pad hit) | 2 fix + 1 예약 |
| 사소 | 2 | 주석 명시 |
치명 #1 fix — VacuumUnit EventBus unsubscribe
기존: _bus.OnBlowSignalChanged += OnBlowSignal 구독만, 해제 없음 -> Part 삭제 시 dead handler 누적.
fix:
- VacuumUnitActuator.Uninitialize() 메서드 신설 — _bus.OnBlowSignalChanged -= OnBlowSignal
- ActuatorDriver.UnregisterActuatorif (actuator is VacuumUnitActuator vu) vu.Uninitialize() (옵션 B: type cast, IActuator 인터페이스 수정 없이 최소 변경)
- ActuatorDriver.UnregisterAll() 헬퍼 + OnDestroy 일괄 cleanup
중대 #1 fix — `_sceneRoot` 의도 명시
기존: Transform _sceneRoot 선언만, 할당 없음 -> 항상 null -> SetParent(null) = 씬 루트.
fix: _sceneRoot = null 명시적 default + 주석 "spec §3 SetParent(SceneRoot), factory00은 별도 SceneRoot GameObject 없음 -> null = Unity scene root (의도)". Ejector + Unit 양쪽.
중대 #2 fix — CaptureDistanceMm 단위 주석 강화
기존: 1f default, "1mm 흡착" 짧은 주석만.
fix: 단위 SSOT 주석 4줄:
- 필드명 suffix "Mm" SSOT (mm 단위)
- Unity Transform = mm scaled 환경 (unit-mm-conversion.md 룰)
- default 1mm = 산업 진공 패드 실측 (0.5~2mm)
- Inspector P1.2 라벨 "(mm)" 명시 예약
중대 #3 — UpdateActuator 미등록
P1.2 (v0.1.241+) 예약 합의 (사용자 [완료]). ActuatorDriver registration + Add 헬퍼 + Inspector UI 동반 사이클.
중간 #1 fix — CommandBackward 사이드 이펙트
기존: CommandBackward() { _blowSignal = true; /* 진공 유지 */ } -> CommandStop 후 재흡착 위험.
fix: _vacuumSignal = false; _blowSignal = true; 명시. SetBlow/SetVacuum도 mutex 적용 (SetBlow(on) -> if (on) _vacuumSignal = false).
중간 #3 fix — pad 자체 OverlapSphere 포함
기존: IsChildOf(_parentPart.cachedTransform) 가드만 — pad가 Part 자식이 아닐 수 있음.
fix: if (go.transform == pad || go.transform.IsChildOf(pad)) continue; 추가. Ejector + Unit 양쪽.
중간 #2 — 단일 파일 3 클래스
P1.2/P2 사이클에서 각 클래스 분리 예약 (Pneumatic 패턴 미러).
사이클 사전 검토 룰 (`spec-vs-codebase-pre-check.md`) 후속 갱신 필요
룰 첫 적용에도 치명 1건 발견. 사전 검토 grep 범위 확대 필요:
- spec brief의 코드 샘플 인용된 이벤트 구독 패턴 (+= / -=) -> unsubscribe 경로 검증 의무
- spec이 가정하는 GameObject/Component 생명주기 -> factory00 ActuatorDriver Register/Unregister 매핑 검증
다음 사이클(v0.1.241)에서 룰 영구화 갱신 예정.
변경 파일
- Assets/Scripts/Actuators/VacuumActuators.cs (+18라인 fix)
- VacuumEjectorActuator: _sceneRoot 의도 주석 / CommandBackward 진공 OFF / SetBlow mutex / pad 가드
- VacuumUnitActuator: _sceneRoot 의도 / Uninitialize() 신설 / pad 가드
- CaptureDistanceMm 단위 주석 강화 (replace_all)
- Assets/Scripts/Actuators/ActuatorDriver.cs (+18라인 fix)
- UnregisterActuator: VacuumUnit type cast -> Uninitialize() 호출
- UnregisterAll() 신설 + OnDestroy 위임
판정 (자가)
치명 0 / 중대 0 (P1.2 예약 1건 사용자 합의) -> PASS 후보. critic 재호출 가능.
다음 단계
- v0.1.241 P1.2 Inspector UI + ActuatorDriver registration (중대 #3 처리 + 풀스택 검증)
- 사전 검토 룰 (spec-vs-codebase-pre-check.md) 갱신 — 이벤트 구독 패턴 검토 의무 추가

v0.1.239 — v0.1.239 — QA-019 에어 진공 패밀리 P1.1 데이터

v0.1.239 v0.1.239 — QA-019 에어 진공 패밀리 P1.1 데이터 zip release notes GitHub
사이클 사전 검토 (룰 spec-vs-codebase-pre-check.md 첫 적용)
| spec 가정 | codebase 실제 | 처리 |
|---|---|---|
| VacuumEjector/Unit/Blower (IActuator) | IActuator SSOT (UpdateActuator/CommandStop/CommandHome) | PASS |
| Part.VacuumEjectors/Units/Blowers | Part는 Servo/Rotary/Pneumatic 3종만 | 3 리스트 신규 추가 |
| VacuumGrasped/Released + BlowSignalChanged | EventBus Pneumatic 패턴 SSOT | 3 이벤트 신규 + Reset 보강 |
| ActuatorDriver 매 프레임 | ActuatorDriver.cs line 43 dt 캐시 | registration 만 추가 (P1.2 사이클) |
| Inspector UI 8 위젯 | PhotoSensor/Servo Inspector 패턴 | P1.2 별도 사이클 |
| Modbus 코일 매핑 | ActuatorPlcBridge 패턴 | P2 별도 사이클 |
판정: PASS — scope 분할 후 진행. v0.1.239 = 데이터+동작만.
QA-019 P1.1 신규 산출물
1) `Assets/Scripts/Events/VacuumEvents.cs` (+76라인 신규)
- VacuumGraspedEvent (ActuatorId / Workpiece / Pad / PressureKpa / Timestamp)
- VacuumReleasedEvent (ActuatorId / Workpiece / PressureKpa / Reason / Timestamp)
- BlowSignalChangedEvent (ActuatorId / IsActive / Timestamp)
- VacuumReleaseReason enum (BlowSignalOn / VacuumOffDecay / AirBlowerEvent)
2) `Assets/Scripts/Events/EventBus.cs` (+6라인)
- OnVacuumGrasped / OnVacuumReleased / OnBlowSignalChanged 3 event
- 각각 Publish overload + Reset() 보강
3) `Assets/Scripts/Actuators/VacuumActuators.cs` (+275라인 신규 — 3 클래스 1 파일)
VacuumEjectorActuator (진공+파기 2신호):
- VacuumPads / CaptureDistanceMm (1mm) / TargetPressureKpa (-85) / ReleasePressureKpa (-10) / PressureDecayRate (20kPa/s)
- IActuator 매핑: Forward=진공ON / Backward=파기ON / Stop=둘다OFF / Home=파기
- UpdateActuator: 파기->즉시해제 / 진공->압력수렴+패드OverlapSphere워크검색 / OFF->자연감쇠
- VacuumGraspedEvent + VacuumReleasedEvent 발행
VacuumUnitActuator (진공만):
- VacuumEjector 동일 데이터 + 파기 신호 X
- _bus.OnBlowSignalChanged += OnBlowSignal 구독 — AirBlower 이벤트 수신 시 해제 (spec §3 시나리오)
- 직접 참조 금지 (spec §4 §1) — EventBus 경유만
AirBlowerActuator (파기만):
- BlowSignal flag만 — BlowSignalChangedEvent 발행
- Edge trigger (signal 변경 시만 발행)
4) `Assets/Scripts/Core/Part.cs` (+6라인)
- List VacuumEjectors
- List VacuumUnits
- List AirBlowers
- Servo/Rotary/Pneumatic 와 동시 부착 가능 (구동부 ≠ 출력부 카테고리, spec §1)
협업자 spec 정합 (vacuum-ejector-summary §3 §4 시나리오)
1. VacuumEjector 흐름: 진공ON -> 패드↔워크 ≤1mm 검사 -> SetParent -> 압력 -85kPa 수렴 -> Grasped 발행 [OK]
2. Ejector 파기: 파기ON -> SetParent(SceneRoot) 즉시해제 -> 압력 0kPa 복귀 -> Released(BlowSignalOn) [OK]
3. Ejector 진공OFF 자연감쇠: 압력 0방향 dt × PressureDecayRate 감쇠 -> ReleasePressureKpa 도달 시 해제 -> Released(VacuumOffDecay) [OK]
4. VacuumUnit + AirBlower 조합: AirBlower 파기ON -> BlowSignalChangedEvent 발행 -> VacuumUnit 구독 -> 해제 -> Released(AirBlowerEvent) [OK]
4대 불변 원칙 검토
- ① 임포트 전용: 워크 Transform 제어 / 3D 편집 X [OK]
- ② 경량 물리: OverlapSphere(radius mm) + SetParent / 리지드바디 X [OK]
- ③ 비코딩 UX: VacuumPad List 슬롯 / P1.2 Inspector 슬롯 바인딩 (별도 사이클) [OK]
- ④ 이벤트 기반: AirBlower -> VacuumUnit 직접 참조 X, EventBus 경유 [OK]
다음 단계
- v0.1.240 P1.2: Inspector UI (3 컴포넌트 분기, VacuumPad 슬롯 바인딩 / 압력 라이브 표시)
- v0.1.241 P2: ActuatorDriver registration + Add 헬퍼 + Modbus 코일 매핑
- 협업자 PM checklist 검증은 P1.2 완료 후 (UI 없이 검증 불가능)
변경 파일
- Assets/Scripts/Events/VacuumEvents.cs (신규 76라인)
- Assets/Scripts/Events/EventBus.cs (+12라인)
- Assets/Scripts/Actuators/VacuumActuators.cs (신규 275라인)
- Assets/Scripts/Core/Part.cs (+6라인)

v0.1.238 — v0.1.238 — Edit Duplicate critic fix (치명 2 + 중대 3 처리)

v0.1.238 v0.1.238 — Edit Duplicate critic fix (치명 2 + 중대 3 처리) zip release notes GitHub
critic 검토 결과 (v0.1.237)
| 등급 | 발견 | 처리 |
|---|---|---|
| 치명 | 2 | 본 사이클 fix |
| 중대 | 3 | 본 사이클 fix |
| 중간 | 2 | 본 사이클 fix |
| 사소 | 2 | 본 사이클 fix |
치명 #1 fix — 어셈블리 자식 Part 미등록
기존: Object.Instantiate가 자식 GameObject까지 복제하지만 Part 객체 등록 안 되어 .twn 저장 누락 + Undo 시 고아 잔존.
P1 가드: 자식 Part 보유 부품은 P2 예약 토스트로 거부.
`csharp
if (_childrenByParentId.TryGetValue(target.id, out var children) && children.Count > 0)
{
FlashToast($"Duplicate: 어셈블리(자식 {children.Count}개) 복제는 P2 — 단일 leaf 부품만 P1");
return;
}
`
P2에서 자식 Part 재귀 등록 구현 예약.
치명 #2 fix — Undo 후 stale dict entry
기존: Undo 시 _partByTransform 제거하지만 _foldExpanded/_partHidden/_hiddenByParent dict 잔존 -> ListView fold/visibility 일관성 깨짐.
fix: Undo 안 dict 3개 모두 정리:
`csharp
_host._foldExpanded?.Remove(_duplicate.id);
_host._partHidden?.Remove(_duplicate.id);
_host._hiddenByParent?.Remove(_duplicate.id);
`
중대 #1 fix — 위치 오프셋 Local X 변경
기존: new Vector3(50f, 0, 0) (World Space) -> 회전된 부품 복제 시 예측 불가 방향.
fix: origGo.transform.right * 50f (Local X) -> 부모 회전 일관.
중대 #2 fix — Destroy 프레임 race -> DestroyImmediate
기존: Object.Destroy(comp)는 프레임 끝 실행 -> 같은 프레임 RebuildCacheAndUI 호출 시 stale Component 접근 위험.
fix: Object.DestroyImmediate(comp) 사용. Play Mode Component 대상 안전.
중대 #3 인지 — DuplicateCommand 이중 책임
GameObject 생명주기 + Part 캐시 동시 소유. VisibilityCommand와 동일 구조라 P1은 그대로 유지. 구조적 분리는 P2 또는 InspectorVM 분리 사이클 (task #39)에 동반.
중간 #1 fix — World/Local 좌표 혼용 주석 명시
Position/Rotation = World, Scale = Local (Part 직렬화 SSOT 그대로 유지).
중간 #2 fix — GUID 8자 -> 16자
Guid.NewGuid().ToString("N").Substring(0, 16) — 2^64 충돌 확률 충분.
사소 fix — 토스트 포맷 통일 (한글)
- Execute: "복제: {name}"
- Redo: "복제 (재실행): {name}"
- Undo: "복제 취소: {name}"
VisibilityCommand "표시/감춤" 한글 패턴 일관.
판정
critic 치명 0 / 중대 0 -> PASS. 사이클 종료 가능.
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~25라인)
- DuplicateSelectedPart — leaf-only 가드 추가
- DuplicateCommand.Execute — Local X 오프셋 + GUID 16자
- DuplicateCommand.Undo — dict 3종 cleanup
- RemoveRuntimeComponents — DestroyImmediate 사용
- 토스트 한글 패턴 통일

v0.1.237 — v0.1.237 — QA-015 Edit Duplicate P1 구현

v0.1.237 v0.1.237 — QA-015 Edit Duplicate P1 구현 zip release notes GitHub
QA-015 Edit Duplicate P1 구현 — Ctrl+D · UndoStack 통합
협업자 spec edit-duplicate (summary/brief/plan/checklist). PM 회신 QA-013 A1 정책:
- 메시 Instance 참조 (Object.Instantiate sharedMesh 자동 공유)
- Material 공유 (sharedMaterials 유지)
- 컴포넌트 제거: ISensor / IActuator / ModbusAddressMap 계열 전체 (Transform/Mesh* 유지)
- 하위 재귀 자동 (Object.Instantiate가 트리 전체 복제)
- Ctrl+D 단축키 + UndoStack push
구현 위치
- Assets/Scripts/Game/Factory00Bootstrap.cs (+~125라인)
- DuplicateSelectedPart() 메서드 (line 6540 부근, VisibilityCommand 옆)
- DuplicateCommand : IEditCommand nested class
- Execute: Object.Instantiate(origGo, parent) + 위치 오프셋 50mm X + RemoveRuntimeComponents + 새 Part 객체 + Parts.Add + _partByTransform 갱신 + UI Rebuild
- Undo: GameObject SetActive(false) + Parts.Remove + 캐시 cleanup + 선택 해제
- Redo: GameObject SetActive(true) + Parts 재추가
- RemoveRuntimeComponents: Transform/MeshFilter/MeshRenderer/Collider 외 MonoBehaviour 전체 Destroy
- Ctrl+D 단축키 (line 3285 부근, Ctrl+Z/Y/A 옆)
- Edit 탭 edit-duplicate 버튼 핸들러 = DuplicateSelectedPart 호출 (Placeholder 제거)
정책 매핑 (PM 회신 QA-013 A1)
| 정책 | 구현 |
|---|---|
| 메시 Instance | Object.Instantiate 기본 sharedMesh 공유 |
| Material 공유 | sharedMaterials 그대로 (renderer.material 사용 금지) |
| 컴포넌트 제외 | RemoveRuntimeComponents — Transform·MeshFilter·MeshRenderer·Collider 제외 모두 Destroy |
| 하위 재귀 | GetComponentsInChildren(true) — 전체 자식 GameObject 순회 |
| Ctrl+D 단축키 | Update() line 3285 — ctrlEdit && !IsAnyTextFieldFocused() && KeyCode.D |
| UndoStack | _undoStack.ExecuteAndPush(new DuplicateCommand(this, target)) |
ID/Name 생성 규칙
- id: {원본id}_copy_{GUID 8자} — 유일성 보장
- name: {원본name} (copy) — 부품 트리 직관적 표시
- 위치: 원본 + Vector3(50f, 0, 0) — 50mm X 오프셋 (Unity Transform = mm scaled, 본 단위 매칭)
검증 시나리오 (PM checklist)
1. 씬에서 부품 1개 선택 -> Edit 탭 Duplicate 클릭 -> 복제본 50mm 옆 생성 [OK]
2. 부품 트리 ListView에 새 항목 출현 [OK]
3. 복제본 Inspector -> Sensor/Servo/Pneumatic 모두 없음 (컴포넌트 제외) [OK]
4. Ctrl+Z -> 복제 취소 (복제본 사라짐) [OK]
5. Ctrl+Y -> 복제 재실행 (복제본 재등장) [OK]
6. Ctrl+D 단축키 동작 확인 [OK]
P2 예약
- 다중 선택 복제 (MultiSelect) — spec 명시 P2
- 오프셋 방향 사용자 설정 — P3
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+125라인)
- line 1846 부근: edit-duplicate 핸들러 (Placeholder -> DuplicateSelectedPart)
- line 3285: Ctrl+D 단축키
- line 6540~6660: DuplicateSelectedPart + DuplicateCommand class
다음 단계
- 협업자 PM checklist 검증 (edit-duplicate-checklist.md)
- QA-019 에어 진공 패밀리 P1 / QA-011 구동부 델타타임 검증
- 38th stable seal 후보 (v0.1.234~237 4 사이클)

v0.1.236 — v0.1.236 — QA-016 모두접기·펴기 부품 헤더 이동 + QA-017 hide 클릭 차단

v0.1.236 v0.1.236 — QA-016 모두접기·펴기 부품 헤더 이동 + QA-017 hide 클릭 차단 zip release notes GitHub
QA-016 fix — 모두펼치기/모두접기 위치 spec 정합 (부품 리스트 헤더)
PM 보고: 모두접기/펼치기 버튼이 리본 메뉴에 있었으나 spec(parts-list-tree-filter-summary.md)은 "부품 리스트 창 상단 툴바" 명시.
변경:
- Assets/UI/MainHUD.uxml (line 23~30) — parts-toolbar 신설. part-section-title 다음·search-host 위 위치.
- [펼치기] [접기] 버튼 2개 (flex-row · flex-grow:1 · font-size:11px)
- Assets/Scripts/Game/Factory00Bootstrap.cs (~15라인) — expandAllAction/collapseAllAction 람다 추출
- 부품 헤더 툴바 parts-toolbar-expand/parts-toolbar-collapse 버튼 = SSOT
- 리본 model-expand-all/model-collapse-all = 동일 람다 호출 (호환 유지)
다음 사이클 예정: Ribbon Model 탭 cmds-model에서 expand-all/collapse-all 버튼 UXML 제거 + 핸들러 cleanup.
QA-017 fix — hide 상태 부품 씬 마우스 클릭 선택 차단
PM 정책 변경 (parts-list-visibility-summary.md r005 Q4):
- 기존 r004: hide 상태에도 씬 클릭 선택 가능
- 변경 r005: hide 상태 씬 클릭 선택 불가, 부품 리스트 클릭 / Inspector 편집은 유지
변경: Assets/Scripts/Game/Factory00Bootstrap.cs
- 신규 헬퍼 IsPartHidden(Part)_partHidden dict 조회
- PickPartUnderMouse (line 3818):
- Physics.Raycast path — Part 찾은 직후 IsPartHidden(pp) -> return null
- fallback bounds.IntersectRay path — 동일 가드 추가
- drag-select PerformDragSelect — 별도 가드 불필요 (r.enabled 체크가 이미 hide 부품 skip)
확인 path:
- 씬 클릭: hide 부품 -> Inspector 미갱신 (선택 차단) [OK]
- 부품 리스트 클릭: 그대로 동작 (PartListSelectionChanged 별도 경로) [OK]
- Inspector 편집: 그대로 동작 (이미 선택된 부품 대상) [OK]
QA-006 진단 로그 / QA-008 휠 누수 fix / QA-014 진단 그대로 유지
v0.1.235 패턴 그대로 누적. 협업자 회신 시 종합 분석.
변경 파일
- Assets/UI/MainHUD.uxml (+5라인) — parts-toolbar 신설
- Assets/Scripts/Game/Factory00Bootstrap.cs (+25라인) — expand/collapse 람다 + IsPartHidden 가드
다음 단계
- 협업자 PM 검증 (QA-014 / QA-006 / QA-008 / QA-016 / QA-017 일괄)
- QA-007 / QA-009 / QA-010 추가 진단 필요
- QA-015 Edit Duplicate / QA-019 에어 진공 / QA-011 구동부 검증 — 회귀 fix 완료 후

v0.1.235 — v0.1.235 — QA-008 휠 누수 fix + QA-006 진단 로그

v0.1.235 v0.1.235 — QA-008 휠 누수 fix + QA-006 진단 로그 zip release notes GitHub
QA-008 fix — Ribbon 명령 영역 휠 -> 씬 카메라 줌 누수 차단
PM 보고 (v0.1.191): "Ribbon 명령 버튼 영역에서 휠 -> 씬 카메라 줌까지 동시 동작 (누수)".
root cause: ribbon-tabs에만 WheelEvent StopPropagation 등록 (v0.1.170 line 1368~1382).
ribbon-commands(60px 명령 영역) 위 휠은 명시적 차단 없음 -> propagation 거쳐 viewport zoom trigger.
fix: ribbon-commands 전체에 WheelEvent TrickleDown 콜백 등록.
- 탭 전환 trigger는 ribbon-tabs 전용 유지 (사용자 명령 영역에서 탭 전환은 비의도)
- 명령 영역 휠은 단순 차단 (씬 카메라 zoom 누수만 막음)
`csharp
ribbonCommands.RegisterCallback(evt => evt.StopPropagation(),
TrickleDown.TrickleDown);
`
PM 검증: Ribbon 8 탭 모든 명령 영역(File/Edit/View/Model/Simulation/Communication/Review/Present)에서 휠 -> 씬 줌 안 일어나는지.
QA-006 진단 로그 — 씬 클릭 선택 불가 회귀 추적
PM 보고 (v0.1.191): "씬 오브젝트 마우스 좌클릭 시 선택 안 됨, Inspector 미갱신".
v0.1.235 진단 로그 (Input.GetMouseButtonDown(0) 분기 line 3013~):
`
[QA-006 진단] LMB_DOWN pos=(x,y) screen=(WxH) ribbonH=N leftW=M inViewport=T/F overUI=T/F overGizmo=T/F
`
가설별 진단 매핑:
| 가설 | 진단 패턴 |
|---|---|
| UI overlay가 viewport 영역 전체 가로채임 (hud-root layout 회귀) | overUI=true 항상 (좌표 무관) |
| ribbon resolvedStyle.height 미계산 -> ribbonH=84 (fallback) 잘못 | ribbonH≠84 또는 inViewport 계산 오류 |
| RuntimeGizmo IsHoveredOrDragging stale 상태 | overGizmo=true 항상 |
| leftW 너무 큼 -> 모든 click이 leftW 안 | leftW=Screen.width-N |
PM 검증: v0.1.235 zip 받아 씬 빈 공간 click + 부품 click + Console Player.log 확인. [QA-006 진단] 라인 패턴 회신.
QA-014 V0.1.234 진단 로그 그대로 유지
[QA-014 진단] 패턴 그대로. View Tab 검증 시 함께 회신 부탁.
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+15라인)
- line 1384 부근 ribbonCommands.RegisterCallback 추가
- line 3017 부근 [QA-006 진단] LMB_DOWN 로그 1줄
다음 단계
- QA-014 / QA-006 / QA-008 모두 PM 검증 결과 회신 대기
- 병행 QA-016/017 (스펙 위반 fix) · QA-004/012/018/020 답변 작성

v0.1.234 — v0.1.234 — QA-014 View Tab 진단 로그

v0.1.234 v0.1.234 — QA-014 View Tab 진단 로그 zip release notes GitHub
QA-014 PM spot-check 회귀 진단 (협업자 보고: v0.1.233 View Tab 전체 무동작)
PM 보고 증상: 카메라 프리셋·Zoom Fit·Save/Load View 슬롯 CRUD 전체 무동작.
정상: Persp/Ortho 토글·마우스 회전·휠 줌.
코드 grep 결과: SetupRibbonShell(1344~1860) 안 BindRibbonViewCommand(1788~1830) 정상.
Ribbon.uxml view-* 11 버튼 정상. 표면적 코드 회귀 흔적 없음 -> 빌드/환경 issue 의심.
추가된 진단 로그 (Player.log + Unity Console)
- [QA-014 진단] SetupRibbonShell ENTRY root=... children=... frame=... — 함수 호출 자체 검증
- [QA-014 진단] BindRibbonViewCommand: Button '...' NOT FOUND in root — Q
- [QA-014 진단] View click name=... toast=... cam=OK|NULL frame=... — 8 프리셋 버튼 click 추적
- [QA-014 진단] view-fit click cam=... parts=... — Zoom Fit
- [QA-014 진단] view-ortho click cam=... — Persp/Ortho
- [QA-014 진단] view-save / view-load click cam=... — slot CRUD
협업자 검증 요청
1. v0.1.234 zip 받아 실행
2. View 탭 클릭 -> 각 버튼 클릭 시도
3. Unity Console (개발자 모드) 또는 %LOCALAPPDATA%LowDefaultCompany actory00Player.log 확인
4. [QA-014 진단] 라인 결과 handshake.md 답변 칸 회신
가설별 진단 출력 매핑
| 가설 | 진단 로그 패턴 |
|---|---|
| SetupRibbonShell 호출 안 됨 | ENTRY 로그 자체 부재 |
| view-* 버튼 Q<> null (UXML 미매칭) | Button '...' NOT FOUND 출력 |
| 버튼은 존재하나 click 못 받음 (overlay/pickingMode) | ENTRY 있고 NOT FOUND 없는데 View click 부재 |
| click 받으나 GetCam() null (CameraViewController 미존재) | View click name=... cam=NULL |
| 모두 정상인데 카메라 미전환 | View click name=... cam=OK 출력되나 시각 변화 X -> SetPresetView 내부 결함 |
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (+18라인)
- SetupRibbonShell 진입 로그 (line 1346)
- BindRibbonViewCommand Q<> null 검출 + click 로그 (line 2470)
- 8 프리셋 + view-fit/ortho/save/load 각각 진단 로그
다음 단계
- 협업자 진단 회신 후 root cause 확정 -> v0.1.235 fix
- 병행: QA-006~009 회귀 fix · QA-016/017 spec 위반 · QA-015 Edit Duplicate

v0.1.233 — v0.1.233 — View slot 메뉴에 저장 시각 표시

v0.1.233 v0.1.233 — View slot 메뉴에 저장 시각 표시 zip release notes GitHub
Unity 신규 기능
- View slot 라벨에 timestamp 추가 — Save 시점 ISO8601 ("yyyy-MM-ddTHH:mm") 저장
- 메뉴 표시: [2] yaw=45° pitch=30° dist=8.5 · 2026-05-17 22:00
- 기존 JSON 호환 (savedAt 필드 없으면 timestamp 없는 라벨 — null 안전)
- 사용자가 어느 slot 이 최신/구버전인지 한눈에 확인
ViewState 신규 필드
- string savedAt — ISO8601 datetime (yyyy-MM-ddTHH:mm)
- JsonUtility 호환 — 기존 5 slot 데이터 손실 없음
- LoadViewState 안 별도 처리 없음 (메뉴 표시 전용)
변경 파일
- Assets/Scripts/Game/CameraViewController.cs (~3라인)
- ViewState.savedAt 필드 신규
- SaveViewState()System.DateTime.Now.ToString("yyyy-MM-ddTHH:mm") 채움
- Assets/Scripts/Game/Factory00Bootstrap.cs (~5라인)
- ShowViewSlotMenu 라벨 formatter 에 ts 분기 추가
- savedAt null/빈 문자열 시 "" 반환 -> 기존 라벨 그대로
Ribbon 8 탭 명령 누계 — 45 명령 (변동 없음)
다음 단계
- v0.1.234+ 37th stable seal 후보 (v0.1.229~233 5 사이클 누적)
- v0.1.235+ Edit Duplicate spec
- task #39 InspectorVM / MotorTableVM 분리

v0.1.232 — v0.1.232 — license.tier 키 마이그레이션 (period -> underscore)

v0.1.232 v0.1.232 — license.tier 키 마이그레이션 (period -> underscore) zip release notes GitHub
SSOT 컨벤션 통일
- 기존 (legacy): factory00.license.tier <- period 사용 (다른 키와 불일치)
- 신규 (canonical): factory00.license_tier <- underscore SSOT 일관성
- 마이그레이션: LicenseManager.Load() 안 1회 자동 처리. 사용자 무개입.
마이그레이션 로직
- 조건: legacy 키 존재 && canonical 키 없음 -> 값 복사 + legacy 삭제
- Idempotent (재실행 안전) — 마이그레이션 완료 후엔 legacy 조건 false -> skip
- Debug.Log 1회 출력 (migrated legacy key '...license.tier' -> '...license_tier' (tier=N))
SSOT 컨벤션 (v0.1.232 영구화)
`
factory00._ <- underscore 만, period 금지
`
이로써 PlayerPrefs 키 13종 모두 동일 컨벤션 (v0.1.230 보고분 마지막 1건 처리 완료).
변경 파일
- Assets/Scripts/License/LicenseTier.cs (~15라인)
- PrefsKey = factory00.license_tier (변경)
- PrefsKeyLegacy = factory00.license.tier (신규 폐기 예정 const)
- Load() 안 마이그레이션 분기 (HasKey check + SetInt + DeleteKey + Save)
영향
- 기존 사용자 (Pro/Enterprise 라이센스 적용된 사용자) — 자동 마이그레이션 손실 없음
- 신규 사용자 — canonical 키만 사용
- 추후 PlayerPrefs grep 시 컨벤션 위반 0건
Ribbon 8 탭 명령 누계 — 45 명령 (변동 없음)
다음 단계
- v0.1.233+ View slot 우클릭 기능 USER-GUIDE 갱신 (docs-only)
- v0.1.234+ Edit Duplicate spec 작성
- v0.1.235+ Communication MX Component placeholder (SDK 대기)
- task #39 InspectorVM / MotorTableVM 분리

v0.1.231 — v0.1.231 — View slot Save 메뉴 sub-menu [덮어쓰기 / 삭제]

v0.1.231 v0.1.231 — View slot Save 메뉴 sub-menu [덮어쓰기 / 삭제] zip release notes GitHub
Unity 신규 기능
- Save View 메뉴 + 채워진 slot -> sub-menu 분기
- 채워진 slot ([2] yaw=45° pitch=30° dist=8.5) hover/click -> sub-menu 펼침
- sub-menu: 덮어쓰기 (기존 SaveViewSlot) · 삭제 (PlayerPrefs.DeleteKey)
- 비어있는 slot ([3] 비어있음) -> 단순 click = 저장 (기존 동작 유지)
- Load View 메뉴 동작 변동 없음 (저장된 slot 만 표시, 단일 click = 복원)
새 헬퍼
- DeleteViewSlot(int slotN) — PlayerPrefs.DeleteKey + active slot 트래킹 reset (해당 slot 이 _activeViewSlot 일 때만) + 토스트
UX 의미
- View P3 multi-slot 시리즈 CRUD 완성 (Save / Load / Delete = 풀 사이클)
- 사용자가 잘못 저장한 slot 정리 가능 -> 5 slot 한도 안에서 더 자유롭게 사용
- ContextMenuElement.Item.children 패턴 활용 (v0.1.231 신규 활용처)
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~35라인)
- ShowViewSlotMenu Save 모드 분기에 parsed != null 조건 sub-menu 추가
- DeleteViewSlot(int) 헬퍼 신규
- active slot reset 로직 (_activeViewSlot == slotN 일 때 0 으로)
Ribbon 8 탭 명령 누계 — 45 명령 (변동 없음, 메뉴 항목 확장)
다음 단계
- v0.1.232+ Edit Duplicate (Part Mesh/Material 복제 매트릭스 spec 필요)
- v0.1.233+ Communication MX Component placeholder 갱신 (SDK 대기)
- license.tier 키 마이그레이션 (legacy -> underscore 컨벤션)
- task #39 InspectorVM / MotorTableVM 분리 (Bootstrap -500~700 라인)

v0.1.230 — v0.1.230 — PlayerPrefs SSOT audit + cleanup

v0.1.230 v0.1.230 — PlayerPrefs SSOT audit + cleanup zip release notes GitHub
SSOT 진단 결과 (전수 grep)
- factory00.* prefix 키 12종 사용 (Bootstrap + SettingsVM + LicenseTier)
- 죽은 키 2개 발견factory00.parts_rows_height / factory00.inspector_height (READ-only)
- 중복 const 1개 발견ViewSlot1Pref (참조 0건)
- 컨벤션 위반 1건 — factory00.license.tier (period 사용, 다른 키는 underscore) -> 마이그레이션 위험으로 보고만
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~3라인)
- ViewSlot1Pref const 제거 (호환 보존 주석은 ViewSlotPrefix 위치로 통합)
- .twn TwnViewSettings 직렬화 시 죽은 키 -> 실 splitter 키와 sync
- partsRowsHeight <- factory00.parts_section_height
- inspectorHeight <- factory00.inspector_section_height
영향
- .twn 저장 시 partsRowsHeight / inspectorHeight 가 정상 splitter 높이 값으로 직렬화 (이전: 항상 0f)
- 향후 .twn LoadProject 시 viewSettings 복원 가능 (이전: 0f 의미없는 데이터)
- 코드 노이즈 1라인 감소
Ribbon 8 탭 명령 누계 — 45 명령 (변동 없음)
다음 단계
- v0.1.231+ Edit Duplicate (Part Mesh/Material 복제 매트릭스 spec 필요)
- v0.1.232+ Communication MX Component placeholder 갱신 (SDK 대기)
- task #39 InspectorVM / MotorTableVM 분리 (Bootstrap -500~700 라인 감축)

v0.1.229 — v0.1.229 — Status 라벨에 활성 View slot 표시

v0.1.229 v0.1.229 — Status 라벨에 활성 View slot 표시 zip release notes GitHub
Unity 신규 기능
- Status 라벨에 활성 View slot 표시 — Save View / Load View 호출 후 View:[2] 형태로 우측 영역 표시
- _activeViewSlot 트래킹 (0 = 표시 없음, 1~5 = 마지막 슬롯)
- SaveViewSlot -> 해당 slot 번호 갱신 + UpdateStatusLabel 즉시 호출
- LoadViewSlot -> 해당 slot 번호 갱신 + UpdateStatusLabel 즉시 호출
- 시작 시 0 -> 표시 없음. 명시적 Save/Load 후에만 라벨 표시.
UX 의미
- v0.1.227~228 multi-slot 시리즈의 시각적 폴리시 마무리
- 사용자가 "지금 어느 slot 상태인지" 한눈에 확인
- Save View slot 2 -> 라벨 View:[2]. Load View slot 4 -> View:[4]
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs (~5라인)
- int _activeViewSlot = 0; 필드 신규
- SaveViewSlot/LoadViewSlot 끝에 _activeViewSlot = slotN; UpdateStatusLabel();
- UpdateStatusLabel 안 production string formatter에 slotLabel 분기 추가
Ribbon 8 탭 명령 누계 — 45 명령 (변동 없음)
- View = 12 (Front/Back/Left/Right/Top/Bottom/Iso/Reset/Fit/Ortho · Save View · Load View)
다음 단계
- v0.1.230+ Edit Duplicate (Part Mesh/Material 복제 매트릭스 spec)
- v0.1.231+ Communication MX Component placeholder 갱신 (SDK 대기)
- task #39 InspectorVM / MotorTableVM 분리 (Bootstrap -500~700 라인 감축)

v0.1.228 — v0.1.228 — View P3 카메라 프리셋 multi-slot (slot 1~5)

v0.1.228 v0.1.228 — View P3 카메라 프리셋 multi-slot (slot 1~5) zip release notes GitHub
Unity 신규 기능
- Save View 클릭 -> ContextMenu 5 slot 표시 (각 slot 현재 저장 상태 라벨)
- [1] 비어있음 또는 [2] yaw=45° pitch=30° dist=8.5
- 선택 시 해당 slot 에 현재 카메라 상태 저장
- Load View 클릭 -> ContextMenu 저장된 slot만 표시 (비어있는 slot skip)
- 모두 비어있으면: Load View: 저장된 slot 없음 (Save View 먼저)
- 선택 시 해당 slot 복원
인프라
- PlayerPrefs: factory00.view_slot{1~5} (JSON 5개)
- ShowViewSlotMenu(Button anchor, bool isSave) 헬퍼 — Save/Load 동일 패턴
- SaveViewSlot(int) / LoadViewSlot(int) 헬퍼 — 단일 slot 처리
- ContextMenuElement.Item.onClick -> slot 캡처 closure
변경 파일
- Assets/UI/Components/Ribbon.uxml — Save/Load View tooltip 갱신
- Assets/Scripts/Game/Factory00Bootstrap.cs (~80 라인)
- ViewSlotPrefix / ViewSlotMax = 5 constants
- ShowViewSlotMenu / SaveViewSlot / LoadViewSlot 헬퍼
- 기존 view-save / view-load 핸들러 -> ShowViewSlotMenu 호출로 단순화
호환성
- ViewSlot1Pref constant 보존 (v0.1.227 저장 데이터 호환)
- 신규 ViewSlotPrefix + "1" = "factory00.view_slot1" 동일 키 — 기존 slot 1 데이터 자동 인계
Ribbon 8 탭 명령 누계 — 45 명령 (개별 명령 수 유지, 메뉴 항목 확장)
- View = 12 (Front/Back/Left/Right/Top/Bottom/Iso/Reset/Fit/Ortho · Save View · Load View)
다음 단계
- v0.1.229+ Status label에 활성 View slot 표시 (선택)
- v0.1.230+ Edit Duplicate (Part 복제 매트릭스 spec 필요)
- task #39 InspectorVM / MotorTableVM 분리

v0.1.227 — v0.1.227 — View P2 카메라 프리셋 (Save/Load View slot 1)

v0.1.227 v0.1.227 — View P2 카메라 프리셋 (Save/Load View slot 1) zip release notes GitHub
Unity 신규 기능
- Save View 버튼 — Ribbon View 탭. 현재 카메라 상태를 slot 1 에 PlayerPrefs JSON 저장
- Load View 버튼 — Ribbon View 탭. slot 1 저장된 상태 복원
- 저장 필드: yaw / pitch / panX/Y/Z / orbitDistance / orthoSize / CameraViewMode (Default/Top/Side/Iso)
- 토스트: View 저장 (slot 1): yaw=45° pitch=30° dist=8.5 / View 복원 (slot 1): ...
- slot 비어있음: Load View: slot 1 비어있음 (Save View 먼저)
인프라
- CameraViewController.SaveViewState() / LoadViewState(ViewState) 신규 메서드
- [System.Serializable] ViewState 클래스 — Unity JsonUtility 호환
- PlayerPrefs SSOT: factory00.view_slot1 (JSON string)
- ApplyMode(CameraViewMode) 호출로 mode 복원 (Top -> Ortho size + position 등)
변경 파일
- Assets/Scripts/Game/CameraViewController.cs (~30 라인) — ViewState 클래스 + Save/Load 메서드
- Assets/UI/Components/Ribbon.uxmlview-save + view-load 버튼
- Assets/Scripts/Game/Factory00Bootstrap.cs (~30 라인) — 핸들러 2개 + ViewSlot1Pref constant
Ribbon 8 탭 명령 누계 — 45 명령
- View = 12 (Front/Back/Left/Right/Top/Bottom/Iso/Reset/Fit/Ortho · Save View · Load View)
협업자 spec 매칭
- studio-view-tab P2 카메라 프리셋 완성 (1 slot — multi-slot은 향후 확장)
다음 단계
- v0.1.228+ View P3 multi-slot (Save View 2/3/4/5 + 컨텍스트 메뉴)
- v0.1.229+ Edit Duplicate (Part Mesh/Material 복제 매트릭스)
- task #39 InspectorVM / MotorTableVM 분리

v0.1.226 — v0.1.226 — File P2 Recent Files (PlayerPrefs + ContextMenu)

v0.1.226 v0.1.226 — File P2 Recent Files (PlayerPrefs + ContextMenu) zip release notes GitHub
Unity 신규 기능
- Recent 버튼 — Ribbon File 탭. 최근 5개 .twn 파일 ContextMenu 표시
- 클릭 -> 버튼 아래 ContextMenuElement 출현
- 항목: 파일명(.twn 확장자 제외) — 클릭 시 OpenTwnPath(path) 호출
- 파일 없음: 최근 파일 없음 (.twn Open/Save 후 누적) 토스트
인프라
- PlayerPrefs SSOT: factory00.recent_files (| separator, 최대 5개)
- LoadRecentFiles(): PlayerPrefs split + System.IO.File.Exists 필터 (삭제된 경로 자동 제외)
- AddToRecent(path): 중복 제거 + prepend + 최대 5개 + PlayerPrefs.Save
- OpenTwnPath(string path) 신규 — cmd-open 핸들러 핵심 로직 추출
- cmd-open + Recent 메뉴 항목 click 모두 동일 path 사용
- try/catch + Load + ApplyTwnPayload + AddToRecent + Bus.Publish(TwnProjectLoadedEvent) 일원화
변경 파일
- Assets/UI/Components/Ribbon.uxmlcmd-recent 버튼 (Open 옆)
- Assets/Scripts/Game/Factory00Bootstrap.cs (~80 라인)
- OpenTwnPath(string path) 신규 (cmd-open 핸들러에서 추출)
- LoadRecentFiles() / AddToRecent(path) 헬퍼
- BindRibbonFileRecentCommand(root) 핸들러 (ContextMenuElement 표시)
- cmd-open 핸들러 단순화 (OpenTwnPath 호출)
- cmd-save/save-as 핸들러에 AddToRecent(path) 추가
- SetupRibbonShell wire 추가
Ribbon 8 탭 명령 누계 — 43 명령
- File = 6 (New · Open · Recent · Save · Save As · Import STEP)
협업자 spec 매칭
- studio-file-tab P2 Recent Files 완성 — TwnProjectLoadedEvent/SavedEvent 인프라 활용 (협업자 spec project-save-format §7)
다음 단계
- v0.1.227+ Edit Duplicate (Part Mesh/Material 복제 매트릭스)
- v0.1.228+ View P2 카메라 프리셋 (Save View / Load View)
- task #39 InspectorVM / MotorTableVM 분리

v0.1.225 — v0.1.225 — Edit Select All (Ribbon + Ctrl+A 단축키)

v0.1.225 v0.1.225 — Edit Select All (Ribbon + Ctrl+A 단축키) zip release notes GitHub
Unity 신규 기능
- Select All 버튼 — Ribbon Edit 탭. placeholder 제거 -> 핸들러 구현
- Ctrl+A 단축키Input.GetKey(LeftControl/RightControl) 가드 + KeyCode.A. TextField focus 시 입력 우선
- SelectAllParts() 신규 헬퍼 (Drag-select 패턴 미러 L6055~6072)
- ClearMaterialHighlight + _selectedParts.Clear + foreach Parts.Add
- _selectedPart = 첫 부품 -> UpdateDetailSectionTitle + RenderInspector
- HighlightSelectedParts + UpdateGizmoTargets + UpdateListViewSelectionFromSelected
- 토스트: Select All: N개 부품 선택 / 부품 없음 = Select All: 부품 없음
변경 파일
- Assets/UI/Components/Ribbon.uxmledit-select-all tooltip 갱신 (v0.1.176 예정 -> Ctrl+A)
- Assets/Scripts/Game/Factory00Bootstrap.cs (~25 라인)
- edit-select-all placeholder 제거 -> () => SelectAllParts() 핸들러
- SelectAllParts() 메서드 신규
- Ctrl+A 단축키 추가 (Ctrl+Z/Y 블록 안)
- Edit Duplicate placeholder 갱신 (v0.1.176 예정 -> 미구현 (Part Mesh/Material 복제 매트릭스 필요))
Ribbon 8 탭 명령 누계 — 42 명령 (Edit Select All placeholder -> 실 핸들러 전환)
- Edit = 6 (Undo · Redo · Delete · Duplicate(미구현) · Select All · Deselect)
협업자 spec 매칭
- studio-edit-tab P1 Select All 완성 (P1 잔존 = Duplicate — 별도 사이클 Part 복제 매트릭스 spec 필요)
다음 단계
- v0.1.226+ File P2 Recent Files (TwnProjectLoadedEvent 구독 + ContextMenu)
- v0.1.227+ 34th stable seal — v0.1.219~226 8 사이클 봉인
- task #39 InspectorVM / MotorTableVM 분리

v0.1.224 — v0.1.224 — Simulation P3 Stop (모든 Actuator Home 복귀)

v0.1.224 v0.1.224 — Simulation P3 Stop (모든 Actuator Home 복귀) zip release notes GitHub
Unity 신규 기능
- Stop 버튼 — Ribbon Simulation 탭. 모든 Actuator CommandHome() 호출
- ActuatorDriver.AllActuators 전수 순회 (IReadOnlyList)
- Servo / Rotary = ActuatorState.HomingReturn -> HomePosition/0° 까지 자동 이동
- Pneumatic = CommandBackward() (강제 후진)
- Pause 상태(timeScale=0) 감지 -> 토스트에 "Resume 후 진행" 안내 (명령 자체는 큐잉)
- 토스트: Stop: N Actuator Home 복귀 또는 Stop: N Actuator Home 복귀 (Pause 상태 — Resume 후 진행)
변경 파일
- Assets/UI/Components/Ribbon.uxmlsim-stop 버튼 추가
- Assets/Scripts/Game/Factory00Bootstrap.cs (~10 라인) — 핸들러
Ribbon 8 탭 명령 누계 — 42 명령
- Simulation = 4 (Signal Simulator · Interface Emulation · Pause · Stop)
SSOT — Actuator IActuator 인터페이스
- CommandHome() 표준 명령. 3 타입 모두 구현 완료
- ServoAxisActuator.CommandHome() -> state=HomingReturn -> HomePosition 까지 _maxVelocity
- RotaryActuatorActuator.CommandHome() -> state=HomingReturn -> 0° wrap-aware
- PneumaticCylinderActuator.CommandHome() -> CommandBackward() (B포트)
협업자 spec 매칭
- studio-simulation-tab P2~P3 모두 완성 — Pause / Stop
다음 단계
- v0.1.225+ Edit 탭 P2 (Undo/Redo 히스토리 패널)
- v0.1.226+ File 탭 P2 (.twn Open 다이얼로그)
- task #39 InspectorVM / MotorTableVM 분리 (Bootstrap -500~700 라인 감축)

v0.1.223 — v0.1.223 — Simulation P2 Pause/Resume 토글 (Time.timeScale)

v0.1.223 v0.1.223 — Simulation P2 Pause/Resume 토글 (Time.timeScale) zip release notes GitHub
Unity 신규 기능
- Pause 버튼 — Ribbon Simulation 탭. Time.timeScale 0/1 토글
- 일시정지: Time.timeScale = 0 -> Actuator UpdateActuator + Sensor polling 모두 정지 (deltaTime 기반)
- 재개: Time.timeScale = 1 -> 정상 진행
- 버튼 텍스트 동적 갱신: "Pause" ↔ "Resume"
- 토스트: 시뮬레이션 일시정지 (timeScale=0) / 시뮬레이션 재개 (timeScale=1)
변경 파일
- Assets/UI/Components/Ribbon.uxmlsim-pause-toggle 버튼 추가
- Assets/Scripts/Game/Factory00Bootstrap.cs (~12 라인) — 핸들러
Ribbon 8 탭 명령 누계 — 41 명령
- Simulation = 3 (Signal Simulator · Interface Emulation · Pause)
알고리즘 선택 사유
- Time.timeScale 0/1 = 모든 deltaTime 기반 로직 한 번에 정지 (Unity 표준 패턴)
- Stop (Home 복귀) = 별도 사이클 — actuator 명령 매트릭스 (Servo CommandStop / Pneumatic ResetToA / Rotary Home) 필요
- 사용자 입력 (마우스/키보드) 은 timeScale 영향 안 받음 -> 일시정지 중에도 시점 변경 / 부품 선택 가능
다음 단계
- v0.1.224+ Simulation P3 Stop (모든 actuator Home 복귀)
- v0.1.225+ Edit 탭 P2 (Undo/Redo 히스토리 패널)
- task #39 InspectorVM / MotorTableVM 분리 (Bootstrap -500~700 라인 감축)

v0.1.222 — v0.1.222 — Review P4 충돌 검사 (AABB pairwise intersect)

v0.1.222 v0.1.222 — Review P4 충돌 검사 (AABB pairwise intersect) zip release notes GitHub
Unity 신규 기능
- Collision 버튼 — Ribbon Review 탭. 선택 2+ 부품 사이 AABB pairwise 충돌 검사
- ComputePartBounds 헬퍼 재사용 (Measure / Angle 와 동일 SSOT)
- Bounds.Intersects() AABB 빠른 검사. Physics.OverlapBox 미사용 (collider 의존성 회피)
- 결과: 겹친 쌍 수 + 첫 3쌍 이름 토스트
- Player.log: [review-collision] HIT {name1} ↔ {name2} 매 쌍 인용 + 합계
- 출력 예시:
- 2 부품 미만: 충돌: 2+ 부품 선택 필요 (현재 N개)
- mesh 없음: 충돌: 부품 mesh 없음
- 겹침 없음: 충돌: 0/N쌍 겹침
- 겹침 있음: 충돌: 5/10쌍 — MotorA↔BracketB, MotorA↔CoverC, BracketB↔ShaftD 외
변경 파일
- Assets/UI/Components/Ribbon.uxmlreview-collision 버튼 + P4 placeholder 제거
- Assets/Scripts/Game/Factory00Bootstrap.cs (~40 라인)
- review-collision 핸들러 (pairwise 이중 루프 + Bounds.Intersects)
Ribbon 8 탭 명령 누계 — 40 명령
- Review = 5 (BBox · Show Hidden · Measure · Angle · Collision)
협업자 spec 매칭
- studio-review-tab P1~P4 모두 완성 — BBox / Hidden / Measure / Angle / Collision
알고리즘 선택 사유
- AABB Intersects = O(N²) 빠름. 산업 어셈블리 ~50~200 부품 한도 충분
- Physics.OverlapBox 미사용 = Unity Physics collider 의존성 회피 (CLAUDE.md 핵심범위 #2 "물리엔진 최소" 일관)
- 정밀 mesh-mesh 검사는 미구현 — 향후 사용자 명시 시 OBB 또는 SAT 추가
다음 단계
- v0.1.223+ Simulation P2 (Play/Pause/Stop 다이얼로그)
- v0.1.224+ Edit 탭 P2 (Undo/Redo 가시화 + 히스토리 패널)
- task #39 InspectorVM / MotorTableVM 분리 (Bootstrap -500~700 라인 감축)

v0.1.221 — v0.1.221 — Model P2.3 Add Pneumatic + Add Rotary (Ribbon Model P2 완성)

v0.1.221 v0.1.221 — Model P2.3 Add Pneumatic + Add Rotary (Ribbon Model P2 완성) zip release notes GitHub
Unity 신규 기능
- Add Pneumatic 버튼 — Ribbon Model 탭. 선택 부품 각각에 PneumaticCylinderActuator 1개 부착
- 부품당 1개 + Servo/Rotary 동시 부착 차단 (헬퍼 안 가드 + 핸들러 skip count)
- 다중 선택 시 = Pneumatic 추가: N 부착 · M skip (이미 부착 또는 Servo/Rotary)
- Add Rotary 버튼 — Ribbon Model 탭. 선택 부품 각각에 RotaryActuator 1개 부착
- 부품당 1개 + Servo 동시 부착 차단
- 다중 선택 시 = Rotary 추가: N 부착 · M skip (이미 부착 또는 Servo)
- 단일 부착 성공 = 헬퍼 자체 토스트 (공압 실린더 추가: PNC-{PartId}-001 / 회전 구동부 추가: ROT-{PartId}-001)
변경 파일
- Assets/UI/Components/Ribbon.uxmlmodel-add-pneumatic + model-add-rotary 버튼 (P2.3 placeholder 제거)
- Assets/Scripts/Game/Factory00Bootstrap.cs (~40 라인)
- model-add-pneumatic 핸들러 (3중 가드)
- model-add-rotary 핸들러 (2중 가드)
Ribbon 8 탭 명령 누계 — 39 명령
- Model = 8 (Selection Info · Expand All · Collapse All · Component Info · Add Sensor · Add Servo · Add Pneumatic · Add Rotary)
협업자 spec 매칭 (Model P2 완성)
- studio-model-tab P2.1~P2.3 모두 부착 가능 — Sensor / Servo / Pneumatic / Rotary 4 타입 완전 지원
가드 매트릭스 SSOT
| 추가 대상 | 부품당 1개 | 동시 부착 차단 |
|---|---|---|
| Sensor | 무제한 (PhotoSensor) | — |
| Servo | 1개 | Rotary |
| Pneumatic | 1개 | Servo · Rotary |
| Rotary | 1개 | Servo |
(Servo↔Rotary는 위치 vs 각도 좌표계 충돌. Pneumatic은 단일 actuator 모델만 지원)
다음 단계
- v0.1.222+ Review P4 충돌 검사 (Physics.OverlapBox)
- v0.1.223+ Simulation P2 (Play/Pause/Stop 다이얼로그)
- task #39 InspectorVM / MotorTableVM 분리 (Bootstrap 슬림화)

v0.1.220 — v0.1.220 — Model P2.2 Add Servo (ServoAxisActuator 부착)

v0.1.220 v0.1.220 — Model P2.2 Add Servo (ServoAxisActuator 부착) zip release notes GitHub
Unity 신규 기능
- Add Servo 버튼 — Ribbon Model 탭에 추가. 선택 부품 각각에 ServoAxisActuator 1개 부착
- AddServoAxisToPart 헬퍼 재사용 (Inspector Servo 추가 패턴 동일)
- 부품당 1개 제한 + Rotary 동시 부착 차단 가드는 헬퍼 안에 이미 존재
- 다중 선택 시 가능한 부품에만 추가 + 부착됨/차단됨 합계 토스트
- 단일 부착 성공 = 구동부 추가: AXIS-{PartId}-001 (헬퍼 자체 토스트)
- 다중 선택 시 = Servo 추가: N 부착 · M skip (이미 부착 또는 Rotary)
- 단일 선택 + 부착 불가 시 = Add Servo: 이미 부착 또는 Rotary 와 동시 부착 불가
변경 파일
- Assets/UI/Components/Ribbon.uxmlmodel-add-servo 버튼 + P2.3 placeholder 갱신
- Assets/Scripts/Game/Factory00Bootstrap.cs (~20 라인)
- model-add-servo 핸들러 추가 (foreach selectedParts + 가드 분기)
Ribbon 8 탭 명령 누계 — 37 명령
- Model = 6 (Selection Info · Expand All · Collapse All · Component Info · Add Sensor · Add Servo)
협업자 spec 매칭
- studio-model-tab P2.2 Add Servo (2/3 컴포넌트 부착 완료)
- P2.3 Add Pneumatic · Add Rotary — 별도 사이클 (Pneumatic/Rotary 생성자 패턴 + Driver 등록 동일)
다음 단계
- v0.1.221+ Model P2.3 Add Pneumatic (PneumaticCylinderActuator 부착)
- v0.1.222+ Model P2.3 Add Rotary (RotaryActuatorActuator 부착)
- v0.1.223+ Review P4 충돌 검사 (Physics.OverlapBox)

v0.1.219 — v0.1.219 — SettingsVM Init Log cleanup (critic deferred 2건)

v0.1.219 v0.1.219 — SettingsVM Init Log cleanup (critic deferred 2건) zip release notes GitHub
critic deferred 처리
- v0.1.218 critic 4차 중간 결함 2건 본 사이클 처리 — Init 경로 Debug.Log 일관성 정리
제거
- SettingsPanelViewModel.cs:132 BindLitToggle Debug.Log("SetValueWithoutNotify({current}) — PlayerPrefs SSOT sync")
- SettingsPanelViewModel.cs:194 BindResolutionDropdown 해상도 변경 Debug.Log("해상도 변경 -> {w}x{h}")
- SettingsPanelViewModel.cs:196 BindResolutionDropdown Debug.Log("현재 = {kResolutionChoices[idx]}")
보존 (production safety)
- Init() Debug.Log("Init 완료") — 1회 lifecycle 표준
- LogError "root null" / "panel NOT FOUND" — production 에러 진단
- LogWarning "BindLitToggle/BindLocalRotationToggle/BindResolutionDropdown SKIP — null 가드" — production warn
- Toggle() LogWarning "panel=null" — production safety
변경 파일
- Assets/Scripts/UI/SettingsPanelViewModel.cs 3 라인 (-3)
- ProjectSettings/ProjectSettings.asset bundleVersion 0.1.218 -> 0.1.219
다음 단계
- v0.1.220+ Model P2.2 Add Servo (ServoAxisActuator 부착)
- v0.1.221+ Model P2.3 Add Pneumatic / Add Rotary
- v0.1.222+ Review P4 충돌 검사

v0.1.218 — v0.1.217 — QA 코드 cascade 정리 (SettingsVM + NavigationMoveEvent)

v0.1.218 v0.1.217 — QA 코드 cascade 정리 (SettingsVM + NavigationMoveEvent) zip release notes GitHub
v0.1.216 critic CONDITIONAL 후속
- v0.1.216 critic 중대 2건 (cycle-critic-review.md fix 후 자가 cascade 검토 의무 위반)
1. SettingsPanelViewModel 동일 패턴 진단 인프라 미처리
2. SearchWidgetViewModel NavigationMoveEvent Debug.Log 누락
- 본 사이클에서 cascade 일괄 정리 — 사용자 AC "QA는 빌드안에 포함시키지 말고 빼라" 100% 충족
제거 (SettingsPanelViewModel.cs)
- GearMouseDownCount / GearClickedCount / EscEventCount / ToggleCallCount 카운터 필드 4종
- OnDiagnostic 콜백 인프라
- [설정] Button.clicked 안 카운터+Invoke+Debug.Log -> _toggleBtn.clicked += Toggle; 단순화
- [설정] MouseDownEvent / PointerDownEvent 진단 콜백 등록 제거
- ESC RegisterCallback 안 EscEventCount++ + OnDiagnostic + Debug.Log 제거 (가드 + Toggle 로직 보존)
- 해상도 변경 OnDiagnostic 호출 제거
- Open() 안 NEXTFRAME panel 진단 schedule 블록 제거
- Toggle() 안 진단 SKIP/FAIL Invoke + Debug.Log 제거 (throttle + null check 보존)
제거 (SearchWidgetViewModel.cs)
- NavigationMoveEvent 콜백 안 Debug.Log 1줄 (PreventDefault + StopPropagation 보존)
제거 (Bootstrap.cs)
- #if DEBUG _settingsVM.OnDiagnostic = msg => FlashToast(...) #endif wire 블록
변경 파일
- Assets/Scripts/UI/SettingsPanelViewModel.cs — 진단 인프라 ~30라인 제거
- Assets/Scripts/UI/SearchWidgetViewModel.cs — Debug.Log 1줄
- Assets/Scripts/Game/Factory00Bootstrap.cs — _settingsVM.OnDiagnostic wire 4줄
- ProjectSettings/ProjectSettings.asset bundleVersion 0.1.216 -> 0.1.217
잔존 grep 검증
- GearMouseDownCount|GearClickedCount|EscEventCount|ToggleCallCount|FocusInCount|FocusOutCount|EscKeyCount|MouseDownCount|OnDiagnostic — Bootstrap/SettingsVM/SearchVM 3 파일 0건
사이클 종료 직전 critic 재호출 의무
v0.1.215 CONDITIONAL -> v0.1.216 CONDITIONAL -> v0.1.217 PASS 기대 (cascade 일괄 처리 완료).
다음 단계
- v0.1.218+ Model P2.2 Add Servo (ServoAxisActuator 부착)
- v0.1.219+ Model P2.3 Add Pneumatic / Add Rotary
- v0.1.220+ Review P4 충돌 검사 (Physics.OverlapBox)

v0.1.217 — v0.1.217 — QA 코드 cascade 정리 (SettingsVM + NavigationMoveEvent)

v0.1.217 v0.1.217 — QA 코드 cascade 정리 (SettingsVM + NavigationMoveEvent) zip release notes GitHub
v0.1.216 critic CONDITIONAL 후속
- v0.1.216 critic 중대 2건 (cycle-critic-review.md fix 후 자가 cascade 검토 의무 위반)
1. SettingsPanelViewModel 동일 패턴 진단 인프라 미처리
2. SearchWidgetViewModel NavigationMoveEvent Debug.Log 누락
- 본 사이클에서 cascade 일괄 정리 — 사용자 AC "QA는 빌드안에 포함시키지 말고 빼라" 100% 충족
제거 (SettingsPanelViewModel.cs)
- GearMouseDownCount / GearClickedCount / EscEventCount / ToggleCallCount 카운터 필드 4종
- OnDiagnostic 콜백 인프라
- [설정] Button.clicked 안 카운터+Invoke+Debug.Log -> _toggleBtn.clicked += Toggle; 단순화
- [설정] MouseDownEvent / PointerDownEvent 진단 콜백 등록 제거
- ESC RegisterCallback 안 EscEventCount++ + OnDiagnostic + Debug.Log 제거 (가드 + Toggle 로직 보존)
- 해상도 변경 OnDiagnostic 호출 제거
- Open() 안 NEXTFRAME panel 진단 schedule 블록 제거
- Toggle() 안 진단 SKIP/FAIL Invoke + Debug.Log 제거 (throttle + null check 보존)
제거 (SearchWidgetViewModel.cs)
- NavigationMoveEvent 콜백 안 Debug.Log 1줄 (PreventDefault + StopPropagation 보존)
제거 (Bootstrap.cs)
- #if DEBUG _settingsVM.OnDiagnostic = msg => FlashToast(...) #endif wire 블록
변경 파일
- Assets/Scripts/UI/SettingsPanelViewModel.cs — 진단 인프라 ~30라인 제거
- Assets/Scripts/UI/SearchWidgetViewModel.cs — Debug.Log 1줄
- Assets/Scripts/Game/Factory00Bootstrap.cs — _settingsVM.OnDiagnostic wire 4줄
- ProjectSettings/ProjectSettings.asset bundleVersion 0.1.216 -> 0.1.217
잔존 grep 검증
- GearMouseDownCount|GearClickedCount|EscEventCount|ToggleCallCount|FocusInCount|FocusOutCount|EscKeyCount|MouseDownCount|OnDiagnostic — Bootstrap/SettingsVM/SearchVM 3 파일 0건
사이클 종료 직전 critic 재호출 의무
v0.1.215 CONDITIONAL -> v0.1.216 CONDITIONAL -> v0.1.217 PASS 기대 (cascade 일괄 처리 완료).
다음 단계
- v0.1.218+ Model P2.2 Add Servo (ServoAxisActuator 부착)
- v0.1.219+ Model P2.3 Add Pneumatic / Add Rotary
- v0.1.220+ Review P4 충돌 검사 (Physics.OverlapBox)

v0.1.216 — v0.1.216 — QA 코드 빌드 제거 2부 (critic 중대 3건 fix)

v0.1.216 v0.1.216 — QA 코드 빌드 제거 2부 (critic 중대 3건 fix) zip release notes GitHub
사용자 명시 후속
- v0.1.215 critic CONDITIONAL -> 중대 3건 본 사이클 처리 (사용자 AC "QA는 빌드안에 포함시키지 말고 빼라" 완전 충족)
critic 지적 처리 (중대 3건 -> 0건)
1. WASD 진단 토스트 블록 제거 (Bootstrap.cs L2914~2925 원본)
- 매 W/A/S/D keydown 시 FlashToast($"{k} keydown tf={tf} input='{searchInput}'") 발화
- 24-redesign-13 디버그 출력으로 production 화면 오염 -> 일괄 삭제
2. MouseDown 진단 Debug.Log 제거 (Bootstrap.cs L2853~2855 원본)
- 매 좌클릭 시 Debug.Log("[input] MouseDown(L) screen=...") 발화
- 24hh 사용자 click 도달 진단 디버그 -> 삭제
3. SearchWidgetViewModel 진단 인프라 폐기
- FocusInCount / FocusOutCount / EscKeyCount / MouseDownCount 카운터 필드 제거
- OnDiagnostic 콜백 인프라 제거
- 24-redesign-9 MouseDown 진단 콜백 등록 제거 (_host.RegisterCallback)
- FocusIn/FocusOut/KeyDown 콜백 안 OnDiagnostic?.Invoke + Debug.Log 삭제 (UI 동작은 보존)
- Bootstrap.cs L2447~2449 #if DEBUG _searchVM.OnDiagnostic = ... wire 제거
- Bootstrap.cs L3165~3179 #if DEBUG 진단 status 블록 제거 (production status로 단순화)
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs 6471 -> ~6440 라인 (-31)
- Assets/Scripts/UI/SearchWidgetViewModel.cs 210 -> ~180 라인 (-30)
- ProjectSettings/ProjectSettings.asset bundleVersion 0.1.215 -> 0.1.216
보존 (production feature)
- SearchVM _input / OnInputChanged / OnEnterPressed / OnEscapeWhileFocused / IME 처리
- SearchVM Focus border 색상 변경 (UX 시각)
- NavigationMoveEvent PreventDefault (WAS 카메라 이동 vs 검색창 입력 분리)
- SettingsPanelViewModel — r20 critic에서 _settingsVM.OnDiagnostic = ... wire 자체가 #if DEBUG 가드. production strip. 본 사이클 범위 외
사이클 종료 직전 critic 재호출 의무
v0.1.215 CONDITIONAL -> v0.1.216 PASS 기대. 잔존 패턴 grep 0건 확인 완료.
다음 단계
- v0.1.217+ Model P2.2 Add Servo (ServoAxisActuator 부착)
- v0.1.218+ Model P2.3 Add Pneumatic / Add Rotary
- v0.1.219+ Review P4 충돌 검사 (Physics.OverlapBox)

v0.1.215 — v0.1.215 — QA 코드 빌드 제거 (사용자 명시)

v0.1.215 v0.1.215 — QA 코드 빌드 제거 (사용자 명시) zip release notes GitHub
사용자 명시
- "QA는 빌드안에 포함시키지 말고 빼라" — production 빌드에 포함된 QA 디버그 코드 ~150라인 일괄 제거
제거 코드 (사용자 마우스/키 입력으로 도달 불가능한 디버그 path)
- F6/F7/F8/F10/Insert 디버그 키 가드 — splitter delta · axis drag PointerEvent SendEvent · drag-select 시뮬
- Time.frameCount == 600 자동 진단_autoDiagFired 1회 발화 splitter+axis 자동 진단
- autoTypeSearch (-qa CLI 플래그) — 5초 후 search field에 "motor" 자동 입력 데모
- -gizmo-rotate CLI — autoSelectFirstMotor 직후 Gizmo Rotate 모드 강제 (G 키 PostMessage 우회용)
- Debug 헬퍼 4 메서드DebugSplitterDelta / DebugAxisDragSimulate / DebugSimulateDragSelectInViewport / DebugSimulateDragSelectOverPanel
- 잔여 필드_autoDiagFired · _autoSearchTriggered · _autoSearchTimer · _gizmoStartRotate · autoTypeSearch · autoTypeSearchQuery · autoTypeSearchDelaySec
보존 코드 (capture-unity-1920.sh 도구 의존)
- F9 키 캡처 — 사용자 수동 캡처. 디버그 키 아닌 export feature
- -capture-now — capture-unity-1920.sh 메인 trigger
- -capture-delay — 모델 로딩 대기
- -capture-exit — 캡처 후 자동 종료
- -qa-out — 캡처 저장 경로 override
- qaCaptureDir 필드 — 위 CLI 처리에서 사용
- F12 InterfaceEmulation 데모 — production demo feature (디버그 아님)
변경 파일
- Assets/Scripts/Game/Factory00Bootstrap.cs 6622 -> 6471 라인 (-151)
- 4 메서드 + 7 필드 + F-키 가드 5건 + frame 600 가드 + autoTypeSearch 처리 블록 + 2 CLI 처리 + _gizmoStartRotate 사용 1건 제거
- Assets/Scripts/UI/SearchWidgetViewModel.cs 주석 1줄 갱신 (autoQA / autoTypeSearch 표현 제거)
외부 자동화 영향
- capture-unity-1920.sh-capture-now / -capture-delay / -capture-exit / -qa-out 4 CLI 그대로 동작. 영향 0
- build-and-publish.sh / publish-build-auto.sh — F-키 / -qa / -gizmo-rotate 사용 안 함. 영향 0
- PostMessage 자동화 (qa-test-by-repro.md §1.2) — F1~F5 / F9 / F11 / F12 그대로 사용. F6~F10/Insert 만 제거
- 사용자 수동 사용 — F9 캡처 / F11 collapse / F12 데모 그대로 동작
사이클 종료 직전 의무 — critic 코드리뷰
- ADR-0022 + qa-real-input-only.md 룰 일관성 검토 의무
- 잔존 참조 grep (autoTypeSearch / DebugXxx / KeyCode.F6~F10 / KeyCode.Insert) 0건 확인 완료
다음 단계
- v0.1.216+ Model P2.2 Add Servo (ServoAxisActuator 부착)
- v0.1.217+ Model P2.3 Add Pneumatic / Add Rotary
- v0.1.218+ Review P4 충돌 검사 (Physics.OverlapBox)

v0.1.214 — v0.1.214 — Model P2.1 Add Sensor + Component Info 단일 상세

v0.1.214 v0.1.214 — Model P2.1 Add Sensor + Component Info 단일 상세 zip release notes GitHub
Unity 신규 기능
- Add Sensor 버튼 — Ribbon Model 탭에 추가. 선택 부품 각각에 PhotoSensorComponent 1개 부착
- AddPhotoSensorToPart 헬퍼 재사용 (이미 Inspector Sensor Remove 옆 패턴 존재)
- 다중 선택 시 N 부품 각각에 1개씩 추가 후 합계 토스트
- 단일 선택 시 헬퍼 자체 토스트만 (센서 추가: SENSOR-{PartId}-{seq})
- Component Info 단일 부품 분기 — 1 부품 선택 시 상세 (부품명 + 부착 컴포넌트 목록), 다중 선택 시 분포 카운트
- 단일 예: [MotorA] Sensor 1 · Servo 1 / [Bracket] None (컴포넌트 미부착)
- 다중 예: Component: Sensor 3 · Servo 2 · Rotary 0 · Pneumatic 1 · None 4
변경 파일
- Assets/UI/Components/Ribbon.uxmlmodel-add-sensor 버튼 추가 + P2.2 placeholder
- Assets/Scripts/Game/Factory00Bootstrap.cs (~30라인)
- model-component-info 핸들러 단일/다중 분기 추가
- model-add-sensor 핸들러 추가 (foreach selectedParts -> AddPhotoSensorToPart)
Ribbon 8 탭 명령 누계 — 36 명령
- Model = 5 (Selection Info · Expand All · Collapse All · Component Info · Add Sensor)
협업자 spec 매칭
- studio-model-tab P2.1 Add Sensor (1/3 컴포넌트 부착 완료)
- P2.2 Add Servo · Add Pneumatic — 별도 사이클 (생성자 패턴 + Driver 등록 필요)
다음 단계
- v0.1.215+ Model P2.2 Add Servo (ServoAxisActuator 부착)
- v0.1.216+ Model P2.3 Add Pneumatic (PneumaticCylinderActuator 부착)
- v0.1.217+ Review P4 충돌 검사 (Physics.OverlapBox)

v0.1.213 — v0.1.213 — Model P2.0 Component Info + build-and-publish 자동 재빌드

v0.1.213 v0.1.213 — Model P2.0 Component Info + build-and-publish 자동 재빌드 zip release notes GitHub
Unity 신규 기능
- Model Component Info 버튼 — Ribbon Model 탭에 추가. 선택 부품들의 부착 컴포넌트 분포 토스트
- 분류: Sensor / Servo / Rotary / Pneumatic / None
- 예: Component: Sensor 2 · Servo 1 · Rotary 0 · Pneumatic 0 · None 5
- P2.1 Add Motor/Sensor/Pneumatic = 별도 사이클 (component 생성 + 직렬화 + Inspector 호출 필요)
하네스 도구 신규
- build-and-publish.sh wrapper 신설 (~70라인) — 1명령으로 빌드 + 자동 재빌드 + publish
- Unity batch 호출 후 dll mtime 검증 (BEFORE -> AFTER)
- mtime 미갱신 시 자동 2차 재빌드 (Unity 6 batch abort 패턴 대응)
- 2회 재빌드도 실패 시 FATAL exit (수동 진단 필요)
- lock 점유/해제 자동 처리
회귀 패턴 분석
- v0.1.209 / v0.1.211 / v0.1.212 = 1차 빌드 abort + 어시스턴트 수동 재빌드 3회
- root cause: Unity 6 batch + WSL bash background 조합 (bee_backend stdout flush 누락)
- 가설 검증: cache hit으로 재빌드가 짧음 (~5s) -> 자동 재빌드 비용 작음
- 본 도구로 자율 사이클 reliability ↑ (1차 abort 보고 없이 자동 처리)
변경 파일
- Assets/UI/Components/Ribbon.uxmlcmds-model 영역에 model-component-info 버튼 + tooltip
- Assets/Scripts/Game/Factory00Bootstrap.cs (~20라인) — clicked 핸들러 + 컴포넌트 분포 카운트
- Tools/qa/build-and-publish.sh (신규) — Unity 빌드 + dll 검증 + 자동 재빌드 + publish
Ribbon 8 탭 명령 누계 — 35 명령
- Model = 4 (Selection Info · Expand All · Collapse All · Component Info)
다음 단계
- v0.1.214+ Model P2.1 Add Sensor/Servo/Pneumatic (선택 부품에 컴포넌트 부착)
- v0.1.215+ Review P4 충돌 검사 (Physics.OverlapBox)
- v0.1.216+ TOC 압축 (stable seal 사이클만 / 최근 N 사이클 / 카테고리 그룹)

v0.1.212 — v0.1.212 — Review P3 Angle + 사이클 TOC 인덱스

v0.1.212 v0.1.212 — Review P3 Angle + 사이클 TOC 인덱스 zip release notes GitHub
Unity 신규 기능
- Review Angle 버튼 — Ribbon Review 탭에 추가. 2부품 선택 시 중점 벡터의 각도 분해 토스트
- XY 평면 각도: Mathf.Atan2(dy, dx) -> 0~360°
- Z경사 (Pitch): Mathf.Atan2(dz, √(dx²+dy²)) -> -90~+90°
- 토스트 예: 각도: XY 45.0° / Z경사 +12.3°
- 3점 각도는 P4 (UX 복잡 — 순서 지정 컨텍스트 메뉴 필요)
publish 도구 신규
- latest-builds.html 사이클 TOC 인덱스 — 상단에 모든 사이클 anchor 링크 자동 표
- AUTO-TOC-START / AUTO-TOC-END marker 신설 (publish-gallery.sh 안 python3 정규식 추출)
- 중복 id 자동 제거 (최신 prepend 발견 = 유지)
- CSS .toc 스타일 (배경 + flex-wrap + hover 골드 톤)
변경 파일
- Assets/UI/Components/Ribbon.uxmlcmds-review 영역에 review-angle 버튼 + tooltip
- Assets/Scripts/Game/Factory00Bootstrap.cs (~25라인) — clicked 핸들러 + 수평/수직 각도 분해
- wiki/publish-gallery.sh — TOC marker inject + python3 인덱스 재생성 + CSS 신규
Ribbon 8 탭 명령 누계 — 34 명령
- Review = 4 (BBox · Show Hidden · Measure · Angle)
- 그 외 8 탭 변동 없음
협업자 spec 매칭
- studio-review-tab P3 각도 (2/3 기능 충족) — XY/Z 분해 완료
- P4: 3점 각도 · 충돌 검사 · 주석 — 별도 사이클
다음 단계
- v0.1.213+ Model P2 컴포넌트 바인딩
- v0.1.214+ Review P4 충돌 검사 (Physics.OverlapBox)
- v0.1.215+ Present P3 프레젠테이션 모드 (UI 숨김)

v0.1.211 — v0.1.211 — Present P2 + 본문 sub-list 변환

v0.1.211 v0.1.211 — Present P2 + 본문 sub-list 변환 zip release notes GitHub
Unity 신규 기능
- Present P2 — Scenario Play 버튼 — Ribbon Present 탭에 추가. 클릭 시 RunInterfaceEmulationDemo() 코루틴 시작 (F12 키와 동등)
- Phase A 어셈블리 -> Phase B 2초 전진+정지 (Sensor 실 감지) -> Phase C Home 복귀
- 이미 실행 중이면 시나리오 이미 실행 중 안내 토스트 (중복 시작 방지)
- Ribbon Present 탭 명령 = 2개 (Screenshot · Scenario Play)
publish 도구 polish (사용자 명시 follow-up)
- sub-list markdown 변환 - (2칸) -> - (margin-left 24px), - (4칸) -> - (margin-left 32px) 들여쓰기 hierarchy 표시
- 직전 v0.1.209 본문에 - review-measure 같은 sub-item이 평문으로 들어가던 결함 fix
- 모든 사이클 본문이 markdown nested list 정상 렌더
변경 파일
- Assets/UI/Components/Ribbon.uxmlcmds-present 영역에 present-scenario-play 버튼 추가
- Assets/Scripts/Game/Factory00Bootstrap.cs (~12라인) — clicked 핸들러 + 중복 실행 가드
- Tools/qa/publish-build-auto.sh — markdown 변환 case 추가 ( - / - 패턴)
Ribbon 8 탭 P1 + P2 명령 누계
- File 5 / Edit 6 / View 10 / Model 3 / Simulation 2 / Communication 2 / Review 3 / Present 2 = 33 명령
- Review P2 (Measure, v0.1.209) + Present P2 (Scenario Play, v0.1.211) 완료
협업자 spec 매칭
- studio-present-tab P2 (Scenario Play 부분) 충족
- studio-present-tab P3: 프레젠테이션 모드 (UI 숨김 / 전체화면) — 별도 사이클
다음 단계
- v0.1.212+ Review P3 각도 측정 (3점 또는 2 벡터)
- v0.1.213+ Model P2 컴포넌트 바인딩
- v0.1.214+ Present P3 프레젠테이션 모드 (UI 숨김)

v0.1.209 — v0.1.209 — Review P2 측정 도구 (점-점 거리)

v0.1.209 v0.1.209 — Review P2 측정 도구 (점-점 거리) zip release notes GitHub
신규 기능
- Measure 버튼 — Ribbon Review 탭에 추가. 정확히 2개 부품 선택 시 두 부품 중점(Bounds.center) 사이 거리 + Δ(x,y,z) mm 토스트
- 선택 != 2 -> 측정: 정확히 2개 선택 필요 (현재 N개) 안내 토스트
- mesh 없는 부품 (예: 빈 그룹 노드) -> 측정: 부품 mesh 없음 토스트
- Player.log 도 거리 + Δ 기록 (소수점 2자리, 디버깅용)
변경 파일
- Assets/UI/Components/Ribbon.uxmlcmds-review 영역에 review-measure 버튼 + tooltip + P3 placeholder
- Assets/Scripts/Game/Factory00Bootstrap.cs (~30라인)
- review-measure clicked 핸들러 (2부품 가드 + Sqrt 거리 계산 + 토스트)
- 신규 헬퍼 Bounds? ComputePartBounds(Part p) (Renderer.bounds 합집합)
- ComputeAllPartsBounds() 리팩토링 (신규 헬퍼 재사용 — 코드 -12라인 +6라인)
단위 일관성
- factory00 Unity Transform = mm scaled (unit-mm-conversion.md 룰)
- Renderer.bounds.center 직접 사용 -> 결과 mm
- 토스트 표시: 거리: 1234.5mm Δ(100.0, 200.0, 300.0) 1자리 소수
협업자 spec 매칭
- studio-review-tab P2 측정 (1/3 기능 충족) — 점-점 거리 완료
- P3: 각도 (3점 / 2벡터) · 충돌 검사 · 주석 — 별도 사이클
다음 단계
- v0.1.210+ Model P2 컴포넌트 바인딩 (Add Motor/Sensor/Pneumatic)
- v0.1.211+ Review P3 각도 측정 (3점 또는 2 벡터)
- v0.1.212+ 단축키 매핑 사이클 (Screenshot=Ctrl+P / Measure=M 등)

v0.1.207 — v0.1.207 — Model 탭 P1 (Selection Info + Tree Expand/Collapse)

v0.1.207 v0.1.207 — Model 탭 P1 (Selection Info + Tree Expand/Collapse) zip release notes GitHub

v0.1.207 — v0.1.207 — Model 탭 P1 (Selection Info + Tree Expand/Collapse)

v0.1.207 v0.1.207 — Model 탭 P1 (Selection Info + Tree Expand/Collapse) zip release notes GitHub

v0.1.206 — v0.1.206 — Review 탭 P1 (BBox + Show Hidden)

v0.1.206 v0.1.206 — Review 탭 P1 (BBox + Show Hidden) zip release notes GitHub

v0.1.206 — v0.1.206 — Review 탭 P1 (BBox + Show Hidden)

v0.1.206 v0.1.206 — Review 탭 P1 (BBox + Show Hidden) zip release notes GitHub

v0.1.205 — v0.1.205 — Present 탭 Screenshot 버튼 P1

v0.1.205 v0.1.205 — Present 탭 Screenshot 버튼 P1 zip release notes GitHub

v0.1.205 — v0.1.205 — Present 탭 Screenshot 버튼 P1

v0.1.205 v0.1.205 — Present 탭 Screenshot 버튼 P1 zip release notes GitHub

v0.1.205 — v0.1.205 — Studio Present 탭 P1 — Screenshot 버튼 활성. Ribbon Present 탭 placeholder 폐기 후 Screenshot 버튼 추가. 클릭 시 ScreenCapture.CaptureScreenshot -> persistentDataPath/Screenshots/factory00_YYYYMMDD_HHMMSS.png 저장 + 토스트 알림. 협업자 spec studio-present-tab P1 충족 (프레젠테이션 모드 / 시나리오 재생은 P2 별도 사이클).

v0.1.205 v0.1.205 — Studio Present 탭 P1 — Screenshot 버튼 활성. Ribbon Present 탭 placeholder 폐기 후 Screenshot 버튼 추가. 클릭 시 ScreenCapture.CaptureScreenshot -> persistentDataPath/Screenshots/factory00_YYYYMMDD_HHMMSS.png 저장 + 토스트 알림. 협업자 spec studio-present-tab P1 충족 (프레젠테이션 모드 / 시나리오 재생은 P2 별도 사이클). zip release notes GitHub

v0.1.204 — v0.1.204 — Modbus Serial + MC Protocol 풀스택 동시 폐기. 사용자 명시 ①: "Windows 환경 전용 — TCP만 구현" -> ModbusSerialDriver.cs 제거. ②: "미츠비시 PLC는 MX컴포넌트만 대응" -> McProtocol/ 6 파일 + EventBus 3 event/Publish/Reset + Bootstrap inspector + Ribbon 버튼 모두 제거. 미츠비시 통신 단일 채널 = Tier C-1 MxBridge (SDK 대기). 분모 14->13->12 -> 12/12 = 100%

v0.1.204 v0.1.204 — Modbus Serial + MC Protocol 풀스택 동시 폐기. 사용자 명시 ①: "Windows 환경 전용 — TCP만 구현" -> ModbusSerialDriver.cs 제거. ②: "미츠비시 PLC는 MX컴포넌트만 대응" -> McProtocol/ 6 파일 + EventBus 3 event/Publish/Reset + Bootstrap inspector + Ribbon 버튼 모두 제거. 미츠비시 통신 단일 채널 = Tier C-1 MxBridge (SDK 대기). 분모 14->13->12 -> 12/12 = 100% zip release notes GitHub

v0.1.204 — v0.1.203 — 하네스 잔여 fix — publish-build-auto.sh Stop-Process retry loop (3회) + critic-gate flag granularity 사이클별 변경 + critic 사소 2건 fix (EventBus 재진입 보호 주석 + UnitId 하드코딩 주석). 진행도 13/14 = 93%

v0.1.204 v0.1.203 — 하네스 잔여 fix — publish-build-auto.sh Stop-Process retry loop (3회) + critic-gate flag granularity 사이클별 변경 + critic 사소 2건 fix (EventBus 재진입 보호 주석 + UnitId 하드코딩 주석). 진행도 13/14 = 93% zip release notes GitHub

v0.1.204 — v0.1.203 — 하네스 잔여 fix — publish-build-auto.sh Stop-Process retry loop (3회) + critic-gate flag granularity 사이클별 변경 + critic 사소 2건 fix (EventBus 재진입 보호 주석 + UnitId 하드코딩 주석). 진행도 13/14 = 93%

v0.1.204 v0.1.203 — 하네스 잔여 fix — publish-build-auto.sh Stop-Process retry loop (3회) + critic-gate flag granularity 사이클별 변경 + critic 사소 2건 fix (EventBus 재진입 보호 주석 + UnitId 하드코딩 주석). 진행도 13/14 = 93% zip release notes GitHub

v0.1.204 — v0.1.203 — 하네스 잔여 fix — publish-build-auto.sh Stop-Process retry loop (3회) + critic-gate flag granularity 사이클별 변경 + critic 사소 2건 fix (EventBus 재진입 보호 주석 + UnitId 하드코딩 주석). 진행도 13/14 = 93%

v0.1.204 v0.1.203 — 하네스 잔여 fix — publish-build-auto.sh Stop-Process retry loop (3회) + critic-gate flag granularity 사이클별 변경 + critic 사소 2건 fix (EventBus 재진입 보호 주석 + UnitId 하드코딩 주석). 진행도 13/14 = 93% zip release notes GitHub

v0.1.203 — v0.1.203 — 하네스 잔여 fix — publish-build-auto.sh Stop-Process retry loop (3회) + critic-gate flag granularity 사이클별 변경 + critic 사소 2건 fix (EventBus 재진입 보호 주석 + UnitId 하드코딩 주석). 진행도 13/14 = 93%

v0.1.203 v0.1.203 — 하네스 잔여 fix — publish-build-auto.sh Stop-Process retry loop (3회) + critic-gate flag granularity 사이클별 변경 + critic 사소 2건 fix (EventBus 재진입 보호 주석 + UnitId 하드코딩 주석). 진행도 13/14 = 93% zip release notes GitHub

v0.1.203 — v0.1.203 — 하네스 잔여 fix — publish-build-auto.sh Stop-Process retry loop (3회) + critic-gate flag granularity 사이클별 변경 + critic 사소 2건 fix (EventBus 재진입 보호 주석 + UnitId 하드코딩 주석). 진행도 13/14 = 93%

v0.1.203 v0.1.203 — 하네스 잔여 fix — publish-build-auto.sh Stop-Process retry loop (3회) + critic-gate flag granularity 사이클별 변경 + critic 사소 2건 fix (EventBus 재진입 보호 주석 + UnitId 하드코딩 주석). 진행도 13/14 = 93% zip release notes GitHub

v0.1.202 — v0.1.202 — critic-gate hook 신설 (경고 모드) + parts-visibility Apply atomic 교체 fix (critic 중대 #1·#2) + critic-gate 패턴 정제 (#3) + 30th stable seal 진입. 진행도 13/14 = 93%

v0.1.202 v0.1.202 — critic-gate hook 신설 (경고 모드) + parts-visibility Apply atomic 교체 fix (critic 중대 #1·#2) + critic-gate 패턴 정제 (#3) + 30th stable seal 진입. 진행도 13/14 = 93% zip release notes GitHub

v0.1.202 — v0.1.202 — critic-gate hook 신설 (경고 모드) + parts-visibility Apply atomic 교체 fix (critic 중대 #1·#2) + critic-gate 패턴 정제 (#3) + 30th stable seal 진입. 진행도 13/14 = 93%

v0.1.202 v0.1.202 — critic-gate hook 신설 (경고 모드) + parts-visibility Apply atomic 교체 fix (critic 중대 #1·#2) + critic-gate 패턴 정제 (#3) + 30th stable seal 진입. 진행도 13/14 = 93% zip release notes GitHub

v0.1.201 — v0.1.201 — parts-visibility .twn 직렬화 통합 (parts-visibility:v1 ExtensionBlock + PartVisibilityMapWrapper) + 하네스 개선 3건 (capture retry / publish kill 선행 / /bump-version 스킬). 진행도 13/14 = 93%

v0.1.201 v0.1.201 — parts-visibility .twn 직렬화 통합 (parts-visibility:v1 ExtensionBlock + PartVisibilityMapWrapper) + 하네스 개선 3건 (capture retry / publish kill 선행 / /bump-version 스킬). 진행도 13/14 = 93% zip release notes GitHub

v0.1.201 — v0.1.201 — parts-visibility .twn 직렬화 통합 (parts-visibility:v1 ExtensionBlock + PartVisibilityMapWrapper) + 하네스 개선 3건 (capture retry / publish kill 선행 / /bump-version 스킬). 진행도 13/14 = 93%

v0.1.201 v0.1.201 — parts-visibility .twn 직렬화 통합 (parts-visibility:v1 ExtensionBlock + PartVisibilityMapWrapper) + 하네스 개선 3건 (capture retry / publish kill 선행 / /bump-version 스킬). 진행도 13/14 = 93% zip release notes GitHub

v0.1.200 — v0.1.200 — critic 중대 4건 일괄 처리. (1) Bootstrap.OnDestroy 3개 panel Unsubscribe — dead handler 회피. (2) ModbusAddressMapWrapper SSOT 이동 Bootstrap inline -> Modbus 네임스페이스 (ModbusAddressMap.cs file-scope). (3) 단축키 inventory wiki SSOT 작성 + C 충돌 0건 확인. (4) McProtocolClient false alarm 확정 — 5파일 모두 존재. 진행도 13/14 = 93%

v0.1.200 v0.1.200 — critic 중대 4건 일괄 처리. (1) Bootstrap.OnDestroy 3개 panel Unsubscribe — dead handler 회피. (2) ModbusAddressMapWrapper SSOT 이동 Bootstrap inline -> Modbus 네임스페이스 (ModbusAddressMap.cs file-scope). (3) 단축키 inventory wiki SSOT 작성 + C 충돌 0건 확인. (4) McProtocolClient false alarm 확정 — 5파일 모두 존재. 진행도 13/14 = 93% zip release notes GitHub

v0.1.199 — v0.1.199 — critic 치명 2건 fix + 29th stable seal 진입. (1) EventBus.Reset() Modbus 5종+MC Protocol 3종 누락 보강 — Play Mode 재진입 dead handler 회피. (2) ModbusAddressMappingPanel OnSignalChanged 200ms throttle scheduler — 폴링 tick 마다 UI 전체 rebuild -> dirty flag + IVisualElementScheduledItem.Every(200) 패턴. 진행도 13/14 = 93%

v0.1.199 v0.1.199 — critic 치명 2건 fix + 29th stable seal 진입. (1) EventBus.Reset() Modbus 5종+MC Protocol 3종 누락 보강 — Play Mode 재진입 dead handler 회피. (2) ModbusAddressMappingPanel OnSignalChanged 200ms throttle scheduler — 폴링 tick 마다 UI 전체 rebuild -> dirty flag + IVisualElementScheduledItem.Every(200) 패턴. 진행도 13/14 = 93% zip release notes GitHub

v0.1.199 — v0.1.199 — critic 치명 2건 fix + 29th stable seal 진입. (1) EventBus.Reset() Modbus 5종+MC Protocol 3종 누락 보강 — Play Mode 재진입 dead handler 회피. (2) ModbusAddressMappingPanel OnSignalChanged 200ms throttle scheduler — 폴링 tick 마다 UI 전체 rebuild -> dirty flag + IVisualElementScheduledItem.Every(200) 패턴. 진행도 13/14 = 93%

v0.1.199 v0.1.199 — critic 치명 2건 fix + 29th stable seal 진입. (1) EventBus.Reset() Modbus 5종+MC Protocol 3종 누락 보강 — Play Mode 재진입 dead handler 회피. (2) ModbusAddressMappingPanel OnSignalChanged 200ms throttle scheduler — 폴링 tick 마다 UI 전체 rebuild -> dirty flag + IVisualElementScheduledItem.Every(200) 패턴. 진행도 13/14 = 93% zip release notes GitHub

v0.1.198 — v0.1.198 — 하강 키 LeftCtrl -> C 변경 (사용자 명시 2026-05-17). Orbit/Default 모드 CameraViewController L353 KeyCode.C. 1인칭은 E/Q 보존. 이력 v0.1.092 LShift -> v0.1.164 LCtrl -> v0.1.198 C. 사유: LCtrl 이 Inspector/Modbus scrubber modifier 와 충돌 위험 0 + WASD 자연 인접. 진행도 13/14 = 93%

v0.1.198 v0.1.198 — 하강 키 LeftCtrl -> C 변경 (사용자 명시 2026-05-17). Orbit/Default 모드 CameraViewController L353 KeyCode.C. 1인칭은 E/Q 보존. 이력 v0.1.092 LShift -> v0.1.164 LCtrl -> v0.1.198 C. 사유: LCtrl 이 Inspector/Modbus scrubber modifier 와 충돌 위험 0 + WASD 자연 인접. 진행도 13/14 = 93% zip release notes GitHub

v0.1.198 — v0.1.198 — 하강 키 LeftCtrl -> C 변경 (사용자 명시 2026-05-17). Orbit/Default 모드 CameraViewController L353 KeyCode.C. 1인칭은 E/Q 보존. 이력 v0.1.092 LShift -> v0.1.164 LCtrl -> v0.1.198 C. 사유: LCtrl 이 Inspector/Modbus scrubber modifier 와 충돌 위험 0 + WASD 자연 인접. 진행도 13/14 = 93%

v0.1.198 v0.1.198 — 하강 키 LeftCtrl -> C 변경 (사용자 명시 2026-05-17). Orbit/Default 모드 CameraViewController L353 KeyCode.C. 1인칭은 E/Q 보존. 이력 v0.1.092 LShift -> v0.1.164 LCtrl -> v0.1.198 C. 사유: LCtrl 이 Inspector/Modbus scrubber modifier 와 충돌 위험 0 + WASD 자연 인접. 진행도 13/14 = 93% zip release notes GitHub

v0.1.197 — v0.1.197 — Modbus Mapping P2.7 — .twn 직렬화 통합. ExtensionBlock key="modbus-address-map:v1" wrapper class JsonUtility. SaveProject Build/ApplyTwnPayload 양방향. 빈 entries 시 block 생략. 진행도 13/14 = 93% (Modbus Mapping P2 영역 .twn 영속성 완결)

v0.1.197 v0.1.197 — Modbus Mapping P2.7 — .twn 직렬화 통합. ExtensionBlock key="modbus-address-map:v1" wrapper class JsonUtility. SaveProject Build/ApplyTwnPayload 양방향. 빈 entries 시 block 생략. 진행도 13/14 = 93% (Modbus Mapping P2 영역 .twn 영속성 완결) zip release notes GitHub

v0.1.196 — v0.1.196 — Modbus Mapping P2.6 — Play Mode 실시간 값 갱신 (spec brief HandOff). EventBus.OnModbusSignalChanged 구독 + _liveValues 캐시 + entry row에 현재값 표시 (Coil/DiscreteInput=ON/OFF, Register=정수). Unsubscribe API 노출. 진행도 13/14 = 93% (Modbus Mapping P2 영역 완성도 강화)

v0.1.196 v0.1.196 — Modbus Mapping P2.6 — Play Mode 실시간 값 갱신 (spec brief HandOff). EventBus.OnModbusSignalChanged 구독 + _liveValues 캐시 + entry row에 현재값 표시 (Coil/DiscreteInput=ON/OFF, Register=정수). Unsubscribe API 노출. 진행도 13/14 = 93% (Modbus Mapping P2 영역 완성도 강화) zip release notes GitHub

v0.1.195 — v0.1.195 — publish-build-auto.sh stale zip 회피 fix. 직전 root cause: 같은 VER로 빌드 재시도 시 zip 이미 존재 -> skip -> 직전 빌드 산출물이 영구 게시. fix: 매번 rm + Compress-Archive 강제 갱신. 코드 변경 0 (도구 fix only). 진행도 13/14 = 93% (도구 안정성 보강)

v0.1.195 v0.1.195 — publish-build-auto.sh stale zip 회피 fix. 직전 root cause: 같은 VER로 빌드 재시도 시 zip 이미 존재 -> skip -> 직전 빌드 산출물이 영구 게시. fix: 매번 rm + Compress-Archive 강제 갱신. 코드 변경 0 (도구 fix only). 진행도 13/14 = 93% (도구 안정성 보강) zip release notes GitHub

v0.1.194 — v0.1.194 — Modbus Mapping P2.5+P2.8 polish — 등록 entry 행에 RegisterType EnumField 추가 (Coil/DiscreteInput/HoldingRegister/InputRegister 4종 사용자 직접 변경 가능). 충돌 검사 자동 재실행. SignalRolePopup은 spec deviation 유지 (단일 역할 prefix 패턴). 진행도 13/14 = 93% (Modbus Mapping P2 영역 polish 보강)

v0.1.194 v0.1.194 — Modbus Mapping P2.5+P2.8 polish — 등록 entry 행에 RegisterType EnumField 추가 (Coil/DiscreteInput/HoldingRegister/InputRegister 4종 사용자 직접 변경 가능). 충돌 검사 자동 재실행. SignalRolePopup은 spec deviation 유지 (단일 역할 prefix 패턴). 진행도 13/14 = 93% (Modbus Mapping P2 영역 polish 보강) zip release notes GitHub

v0.1.194 — v0.1.194 — Modbus Mapping P2.5+P2.8 polish — 등록 entry 행에 RegisterType EnumField 추가 (Coil/DiscreteInput/HoldingRegister/InputRegister 4종 사용자 직접 변경 가능). 충돌 검사 자동 재실행. SignalRolePopup은 spec deviation 유지 (단일 역할 prefix 패턴). 진행도 13/14 = 93% (Modbus Mapping P2 영역 polish 보강)

v0.1.194 v0.1.194 — Modbus Mapping P2.5+P2.8 polish — 등록 entry 행에 RegisterType EnumField 추가 (Coil/DiscreteInput/HoldingRegister/InputRegister 4종 사용자 직접 변경 가능). 충돌 검사 자동 재실행. SignalRolePopup은 spec deviation 유지 (단일 역할 prefix 패턴). 진행도 13/14 = 93% (Modbus Mapping P2 영역 polish 보강) zip release notes GitHub

v0.1.194 — v0.1.194 — Modbus Mapping P2.5+P2.8 polish — 등록 entry 행에 RegisterType EnumField 추가 (Coil/DiscreteInput/HoldingRegister/InputRegister 4종 사용자 직접 변경 가능). 충돌 검사 자동 재실행. SignalRolePopup은 spec deviation 유지 (단일 역할 prefix 패턴). 진행도 13/14 = 93% (Modbus Mapping P2 영역 polish 보강)

v0.1.194 v0.1.194 — Modbus Mapping P2.5+P2.8 polish — 등록 entry 행에 RegisterType EnumField 추가 (Coil/DiscreteInput/HoldingRegister/InputRegister 4종 사용자 직접 변경 가능). 충돌 검사 자동 재실행. SignalRolePopup은 spec deviation 유지 (단일 역할 prefix 패턴). 진행도 13/14 = 93% (Modbus Mapping P2 영역 polish 보강) zip release notes GitHub

v0.1.194 — v0.1.194 — Modbus Mapping P2.5+P2.8 polish — 등록 entry 행에 RegisterType EnumField 추가 (Coil/DiscreteInput/HoldingRegister/InputRegister 4종 사용자 직접 변경 가능). 충돌 검사 자동 재실행. SignalRolePopup은 spec deviation 유지 (단일 역할 prefix 패턴). 진행도 13/14 = 93% (Modbus Mapping P2 영역 polish 보강)

v0.1.194 v0.1.194 — Modbus Mapping P2.5+P2.8 polish — 등록 entry 행에 RegisterType EnumField 추가 (Coil/DiscreteInput/HoldingRegister/InputRegister 4종 사용자 직접 변경 가능). 충돌 검사 자동 재실행. SignalRolePopup은 spec deviation 유지 (단일 역할 prefix 패턴). 진행도 13/14 = 93% (Modbus Mapping P2 영역 polish 보강) zip release notes GitHub

v0.1.194 — v0.1.194 — Modbus Mapping P2.5+P2.8 polish — 등록 entry 행에 RegisterType EnumField 추가 (Coil/DiscreteInput/HoldingRegister/InputRegister 4종 사용자 직접 변경 가능). 충돌 검사 자동 재실행. SignalRolePopup은 spec deviation 유지 (단일 역할 prefix 패턴). 진행도 13/14 = 93% (Modbus Mapping P2 영역 polish 보강)

v0.1.194 v0.1.194 — Modbus Mapping P2.5+P2.8 polish — 등록 entry 행에 RegisterType EnumField 추가 (Coil/DiscreteInput/HoldingRegister/InputRegister 4종 사용자 직접 변경 가능). 충돌 검사 자동 재실행. SignalRolePopup은 spec deviation 유지 (단일 역할 prefix 패턴). 진행도 13/14 = 93% (Modbus Mapping P2 영역 polish 보강) zip release notes GitHub

v0.1.194 — v0.1.194 — Modbus Mapping P2.5+P2.8 polish — 등록 entry 행에 RegisterType EnumField 추가 (Coil/DiscreteInput/HoldingRegister/InputRegister 4종 사용자 직접 변경 가능). 충돌 검사 자동 재실행. SignalRolePopup은 spec deviation 유지 (단일 역할 prefix 패턴). 진행도 13/14 = 93% (Modbus Mapping P2 영역 polish 보강)

v0.1.194 v0.1.194 — Modbus Mapping P2.5+P2.8 polish — 등록 entry 행에 RegisterType EnumField 추가 (Coil/DiscreteInput/HoldingRegister/InputRegister 4종 사용자 직접 변경 가능). 충돌 검사 자동 재실행. SignalRolePopup은 spec deviation 유지 (단일 역할 prefix 패턴). 진행도 13/14 = 93% (Modbus Mapping P2 영역 polish 보강) zip release notes GitHub

v0.1.193 — 28th stable seal — v0.1.187~192 6사이클 누적 (Modbus 시리즈 완결 + MC Protocol 풀스택). Modbus Mapping P2.1~4 (드래그앤드롭+충돌+IntField+ModbusType 4종) · Modbus TCP Inspector · MC Protocol Driver+Component+Inspector (3E frame, MELSOFT 의존 0). critic 치명 2 + 중대 4 fix. 진행도 13/14 = 93%

v0.1.193 28th stable seal — v0.1.187~192 6사이클 누적 (Modbus 시리즈 완결 + MC Protocol 풀스택). Modbus Mapping P2.1~4 (드래그앤드롭+충돌+IntField+ModbusType 4종) · Modbus TCP Inspector · MC Protocol Driver+Component+Inspector (3E frame, MELSOFT 의존 0). critic 치명 2 + 중대 4 fix. 진행도 13/14 = 93% zip release notes GitHub

v0.1.192 — v0.1.192 — MC Protocol Inspector Panel (Communication 탭). 상태 배지 + Host:Port/Polling/Timeout + 폴링 통계 + 연결 history 8건 + Reconnect/Disconnect. ModbusTcpInspectorPanel 패턴 미러. 진행도 13/14 = 93% (Tier C-3 MC Protocol Component+Inspector 풀스택 완성)

v0.1.192 v0.1.192 — MC Protocol Inspector Panel (Communication 탭). 상태 배지 + Host:Port/Polling/Timeout + 폴링 통계 + 연결 history 8건 + Reconnect/Disconnect. ModbusTcpInspectorPanel 패턴 미러. 진행도 13/14 = 93% (Tier C-3 MC Protocol Component+Inspector 풀스택 완성) zip release notes GitHub

v0.1.191 — v0.1.191 — MC Protocol Component + Events (3종) + PlcDeviceMap + EventBus 통합. McProtocolDriverComponent (백그라운드 Thread + ConcurrentQueue main-thread dispatch) + Event publish (Connection/Value/Tick). Inspector Panel은 v0.1.192 deferred. 진행도 12/14 = 86% (변동 없음 — Tier C-3 MC Protocol Component 보강)

v0.1.191 v0.1.191 — MC Protocol Component + Events (3종) + PlcDeviceMap + EventBus 통합. McProtocolDriverComponent (백그라운드 Thread + ConcurrentQueue main-thread dispatch) + Event publish (Connection/Value/Tick). Inspector Panel은 v0.1.192 deferred. 진행도 12/14 = 86% (변동 없음 — Tier C-3 MC Protocol Component 보강) zip release notes GitHub

v0.1.190 — v0.1.190 — Mitsubishi MC Protocol Driver P1 (3E frame = SLMP 3E, TCP 직접 통신). IMcProtocolDriver + PlcDeviceType enum (D/M/Y/X/W/L) + McProtocolTcpDriver (Batch Read/Write Word+Bit, 포트 5007, MELSOFT 의존 0). Component/Inspector 별도 사이클. 핵심 16건 spec 중 15건 완료 (94%)

v0.1.190 v0.1.190 — Mitsubishi MC Protocol Driver P1 (3E frame = SLMP 3E, TCP 직접 통신). IMcProtocolDriver + PlcDeviceType enum (D/M/Y/X/W/L) + McProtocolTcpDriver (Batch Read/Write Word+Bit, 포트 5007, MELSOFT 의존 0). Component/Inspector 별도 사이클. 핵심 16건 spec 중 15건 완료 (94%) zip release notes GitHub

v0.1.189 — v0.1.189 — Modbus ModbusRegisterType P2.4 확장 — DiscreteInput (FC 0x02) + InputRegister (FC 0x04) 추가. IModbusDriver 인터페이스 + TcpDriver 구현 + Serial stub + Component PollLoop 4 type switch. 핵심 16건 spec 중 14건 완료 (88%, P2.4 추가 보강)

v0.1.189 v0.1.189 — Modbus ModbusRegisterType P2.4 확장 — DiscreteInput (FC 0x02) + InputRegister (FC 0x04) 추가. IModbusDriver 인터페이스 + TcpDriver 구현 + Serial stub + Component PollLoop 4 type switch. 핵심 16건 spec 중 14건 완료 (88%, P2.4 추가 보강) zip release notes GitHub

v0.1.188 — v0.1.188 — Modbus TCP Inspector Panel (Communication 탭). 연결 상태 실시간 배지 + 폴링 통계 (총 ticks · registers · elapsed ms) + 연결 history 8건 + Reconnect/Disconnect 버튼. EventBus OnModbusConnectionChanged + OnModbusPollingTick 구독. 핵심 16건 spec 중 14건 완료 (88%)

v0.1.188 v0.1.188 — Modbus TCP Inspector Panel (Communication 탭). 연결 상태 실시간 배지 + 폴링 통계 (총 ticks · registers · elapsed ms) + 연결 history 8건 + Reconnect/Disconnect 버튼. EventBus OnModbusConnectionChanged + OnModbusPollingTick 구독. 핵심 16건 spec 중 14건 완료 (88%) zip release notes GitHub

v0.1.188 — v0.1.188 — Modbus TCP Inspector Panel (Communication 탭). 연결 상태 실시간 배지 + 폴링 통계 (총 ticks · registers · elapsed ms) + 연결 history 8건 + Reconnect/Disconnect 버튼. EventBus OnModbusConnectionChanged + OnModbusPollingTick 구독. 핵심 16건 spec 중 14건 완료 (88%)

v0.1.188 v0.1.188 — Modbus TCP Inspector Panel (Communication 탭). 연결 상태 실시간 배지 + 폴링 통계 (총 ticks · registers · elapsed ms) + 연결 history 8건 + Reconnect/Disconnect 버튼. EventBus OnModbusConnectionChanged + OnModbusPollingTick 구독. 핵심 16건 spec 중 14건 완료 (88%) zip release notes GitHub

v0.1.187 — v0.1.187 — Modbus Mapping P2.1~3 (드래그앤드롭 + 충돌 실시간 검사 + 주소 IntField 편집). 협업자 spec 통신/modbus-address-mapping HandOff 완전 달성. 핵심 16건 spec 중 13건 완료 (81%)

v0.1.187 v0.1.187 — Modbus Mapping P2.1~3 (드래그앤드롭 + 충돌 실시간 검사 + 주소 IntField 편집). 협업자 spec 통신/modbus-address-mapping HandOff 완전 달성. 핵심 16건 spec 중 13건 완료 (81%) zip release notes GitHub

v0.1.187 — v0.1.187 — Modbus Mapping P2.1~3 (드래그앤드롭 + 충돌 실시간 검사 + 주소 IntField 편집). 협업자 spec 통신/modbus-address-mapping HandOff 완전 달성. 핵심 16건 spec 중 13건 완료 (81%)

v0.1.187 v0.1.187 — Modbus Mapping P2.1~3 (드래그앤드롭 + 충돌 실시간 검사 + 주소 IntField 편집). 협업자 spec 통신/modbus-address-mapping HandOff 완전 달성. 핵심 16건 spec 중 13건 완료 (81%) zip release notes GitHub

v0.1.187 — v0.1.187 — Modbus Mapping P2.1~3 (드래그앤드롭 + 충돌 실시간 검사 + 주소 IntField 편집). 협업자 spec 통신/modbus-address-mapping HandOff 완전 달성. 핵심 16건 spec 중 13건 완료 (81%)

v0.1.187 v0.1.187 — Modbus Mapping P2.1~3 (드래그앤드롭 + 충돌 실시간 검사 + 주소 IntField 편집). 협업자 spec 통신/modbus-address-mapping HandOff 완전 달성. 핵심 16건 spec 중 13건 완료 (81%) zip release notes GitHub

v0.1.186 — 27th stable seal — v0.1.176~185 10사이클 누적 봉인 (Studio 인프라 + 협업자 spec Tier A 3 + Tier C-4/C-5 + Pneumatic P2 + 빌드 hook 완전 자동). 핵심 16건 spec 중 12건 완료 (75%)

v0.1.186 27th stable seal — v0.1.176~185 10사이클 누적 봉인 (Studio 인프라 + 협업자 spec Tier A 3 + Tier C-4/C-5 + Pneumatic P2 + 빌드 hook 완전 자동). 핵심 16건 spec 중 12건 완료 (75%) zip release notes GitHub

v0.1.185 — A-2 Modbus Serial Driver P1 — System.IO.Ports.SerialPort + RTU CRC16 다항식 0xA001 + IModbusDriver 인터페이스 공유 (TCP/Serial 동일 API) + FC 0x01/0x03/0x05/0x06

v0.1.185 A-2 Modbus Serial Driver P1 — System.IO.Ports.SerialPort + RTU CRC16 다항식 0xA001 + IModbusDriver 인터페이스 공유 (TCP/Serial 동일 API) + FC 0x01/0x03/0x05/0x06 zip release notes GitHub

v0.1.185 — A-2 Modbus Serial Driver P1 — System.IO.Ports.SerialPort + RTU CRC16 다항식 0xA001 + IModbusDriver 인터페이스 공유 (TCP/Serial 동일 API) + FC 0x01/0x03/0x05/0x06

v0.1.185 A-2 Modbus Serial Driver P1 — System.IO.Ports.SerialPort + RTU CRC16 다항식 0xA001 + IModbusDriver 인터페이스 공유 (TCP/Serial 동일 API) + FC 0x01/0x03/0x05/0x06 zip release notes GitHub

v0.1.184 — Modbus Address Mapping Editor P2.0 — 등록 매핑 목록 + 컴포넌트별 후보 (PhotoSensor/ServoAxis 5 역할/Pneumatic 4 역할) 자동 추출 + + 할당 버튼 + Ribbon Communication 탭 wiring

v0.1.184 Modbus Address Mapping Editor P2.0 — 등록 매핑 목록 + 컴포넌트별 후보 (PhotoSensor/ServoAxis 5 역할/Pneumatic 4 역할) 자동 추출 + + 할당 버튼 + Ribbon Communication 탭 wiring zip release notes GitHub

v0.1.183 — A-1 PneumaticCylinder P2 — RotaryPneumatic 회전 타입 (PneumaticType enum / 각도+스토퍼+회전축+CW·CCW / Quaternion.AngleAxis 회전 + Inspector 분기) — A-1 모듈 100% 완성

v0.1.183 A-1 PneumaticCylinder P2 — RotaryPneumatic 회전 타입 (PneumaticType enum / 각도+스토퍼+회전축+CW·CCW / Quaternion.AngleAxis 회전 + Inspector 분기) — A-1 모듈 100% 완성 zip release notes GitHub

v0.1.182 — A-3 SignalSimulatorPanel P1 — 런타임 UI Toolkit 패널 (씬 ISensor/IActuator 자동 검색 + 코일 토글/Reg 입력 즉시 ModbusSignalChangedEvent 발행 + Ribbon Simulation 탭 wiring)

v0.1.182 A-3 SignalSimulatorPanel P1 — 런타임 UI Toolkit 패널 (씬 ISensor/IActuator 자동 검색 + 코일 토글/Reg 입력 즉시 ModbusSignalChangedEvent 발행 + Ribbon Simulation 탭 wiring) zip release notes GitHub

v0.1.181 — A-2 Modbus TCP P1.3 — ModbusTcpDriverComponent MonoBehaviour (백그라운드 폴링 thread + 연속 주소 그룹핑 + 값 변화 감지 + 메인 스레드 dispatch + 재연결 3회 threshold)

v0.1.181 A-2 Modbus TCP P1.3 — ModbusTcpDriverComponent MonoBehaviour (백그라운드 폴링 thread + 연속 주소 그룹핑 + 값 변화 감지 + 메인 스레드 dispatch + 재연결 3회 threshold) zip release notes GitHub

v0.1.180 — A-2 Modbus TCP P1.2 — ModbusTcpDriver (TcpClient + MBAP 프레임 빌드/파싱 + 0x01/0x03/0x05/0x06 FC + signed 16-bit + thread-safe lock)

v0.1.180 A-2 Modbus TCP P1.2 — ModbusTcpDriver (TcpClient + MBAP 프레임 빌드/파싱 + 0x01/0x03/0x05/0x06 FC + signed 16-bit + thread-safe lock) zip release notes GitHub

v0.1.179 — A-2 Modbus TCP P1.1 — IModbusDriver 인터페이스 + ModbusEvents 5종 (Connection/Signal/WriteCommand/WriteResult/PollingTick)

v0.1.179 A-2 Modbus TCP P1.1 — IModbusDriver 인터페이스 + ModbusEvents 5종 (Connection/Signal/WriteCommand/WriteResult/PollingTick) zip release notes GitHub

v0.1.178 — auto-publish (Hook)

v0.1.178 auto-publish (Hook) zip release notes GitHub

v0.1.177 — auto-publish (Hook)

v0.1.177 auto-publish (Hook) zip release notes GitHub

v0.1.176 — Project Save Format .twn P1 (TwnProjectFile + AES-256-CBC+HMAC 인증암호화 + File 탭 핸들러 4종)

v0.1.176 Project Save Format .twn P1 (TwnProjectFile + AES-256-CBC+HMAC 인증암호화 + File 탭 핸들러 4종) zip release notes GitHub

v0.1.175 — Edit Tab P1 인프라 — UndoStack + IEditCommand + VisibilityCommand + Ctrl+Z/Y + Delete 키

v0.1.175 Edit Tab P1 인프라 — UndoStack + IEditCommand + VisibilityCommand + Ctrl+Z/Y + Delete 키 zip release notes GitHub

v0.1.174 — 협업자 View Tab P1 — 카메라 프리셋 7방향(Front/Back/Left/Right/Top/Bottom/Iso) + Reset + Zoom Fit + Persp/Ortho 토글

v0.1.174 협업자 View Tab P1 — 카메라 프리셋 7방향(Front/Back/Left/Right/Top/Bottom/Iso) + Reset + Zoom Fit + Persp/Ortho 토글 zip release notes GitHub

v0.1.173 — 협업자 view/hide P1 마무리 — 다중 선택 일괄 + ObjectVisibilityChangedEvent EventBus 발행

v0.1.173 협업자 view/hide P1 마무리 — 다중 선택 일괄 + ObjectVisibilityChangedEvent EventBus 발행 zip release notes GitHub

v0.1.172 — 협업자 view/hide P1 — VisibilityState + cascade + ListView 눈 아이콘 ○/X + 회색/반투명 시각화

v0.1.172 협업자 view/hide P1 — VisibilityState + cascade + ListView 눈 아이콘 ○/X + 회색/반투명 시각화 zip release notes GitHub

v0.1.171 — critic deferred cleanup — _topbarEl rename + RibbonTabDef struct (병렬 배열 mismatch 위험 0)

v0.1.171 critic deferred cleanup — _topbarEl rename + RibbonTabDef struct (병렬 배열 mismatch 위험 0) zip release notes GitHub

v0.1.170 — Ribbon Shell ViewModel + 자체 TopBar 일괄 제거 (옵션A · critic CONDITIONAL fix 포함)

v0.1.170 Ribbon Shell ViewModel + 자체 TopBar 일괄 제거 (옵션A · critic CONDITIONAL fix 포함) zip release notes GitHub

v0.1.169 — Ribbon Shell P1 골격 — 옵션A 채택 (자체 TopBar 폐기 시작)

v0.1.169 Ribbon Shell P1 골격 — 옵션A 채택 (자체 TopBar 폐기 시작) zip release notes GitHub

v0.1.166 — Inspector XYZ scrubber + drag PointerEvent B-path 검증

v0.1.166 Inspector XYZ scrubber + drag PointerEvent B-path 검증 zip release notes GitHub

v0.1.165 — Inspector axis drag hover cursor + USS hint

v0.1.165 Inspector axis drag hover cursor + USS hint zip release notes GitHub

v0.1.164 — 사용자 4건 fix — Shift->Ctrl 하강 / motor scroll / XYZ drag / splitter UX

v0.1.164 사용자 4건 fix — Shift->Ctrl 하강 / motor scroll / XYZ drag / splitter UX zip release notes GitHub

v0.1.163 — 버그 fix — drag-select panel 가드 + 상하 splitter USS flex-grow 제거

v0.1.163 버그 fix — drag-select panel 가드 + 상하 splitter USS flex-grow 제거 zip release notes GitHub

v0.1.162 — RotaryActuator P1.2 — Driver 등록 + Bootstrap 통합

v0.1.162 RotaryActuator P1.2 — Driver 등록 + Bootstrap 통합 zip release notes GitHub

v0.1.161 — RotaryActuator P1.1 데이터 구현 (26th stable seal)

v0.1.161 회전 구동축 모듈 P1.1 데이터 구현 — `RotaryActuatorActuator` (~170라인) `IActuator` 구현. **Mathf.MoveTowards** 각속도(°/s) 기반 보간 + **Mathf.DeltaAngle** wrap-aware (360°↔-360° 경계 안전) + **Quaternion.AngleAxis** localRotation 갱신 + 0.1° 임계값(jitter 방지). `AxisAngleChangedEvent` + `EventBus.OnAxisAngle` 추가. ServoAxisActuator 선형 patten 미러. **26th stable** — Photosensor·Servo·Emulation·RotaryActuator 데이터 4 모듈 완성. git commit 483527c (21 files +1831/-24, push 안 함). stable zip · build zip · release-notes · spec

v0.1.160 — RotaryActuator spec 작성

v0.1.160 회전 구동축 spec 문서 `2026-05-12-rotary-actuator.md` (340라인, §0~§13) 작성. ServoAxisActuator 패턴 미러 — IActuator 구현 + 각속도(°/s) Mathf.MoveTowards + Quaternion.AngleAxis localRotation. P1.1 데이터(다음 사이클) / P1.2 Bootstrap 통합 / P1.3 Inspector UI / P2 Modbus bridge / P3 메이커 프리셋 (MR-J5 / SGM7J / Minas A6) 분할 5사이클 예약. spec · release-notes

v0.1.159 — USER-GUIDE 25 stable 기준 갱신 (doc-cycle)

v0.1.159 USER-GUIDE 25 stable 누적 시점(v0.1.158) 기준 통합 문서 갱신. Photosensor·Servo·Interface Emulation 3 모듈 사용법 + 단축키 표(F12 시연 추가) + 외부 URL 다운로드 안내. doc-only 사이클 (코드 변경 없음 · bundleVersion bump 없음). release-notes

v0.1.158 — Interface Emulation P2 (Phase B 실 감지) + 25th stable seal

v0.1.158 Phase B 정지 트리거를 단순 2초 timer -> **EventBus.OnSensorStateChanged 실 감지** 로 전환. 코일 10 + Value=true 발화 시 즉시 actuator.CommandStop(). 5s deadline fallback (Sensor 범위 밖 정직 토스트). SensingDistance 0.1->0.3m / Angle 30->45° 부채꼴 (감지 가능성 향상). PhotoSensor self-detect 회피 `IsChildOf(selfRoot)` 이미 존재. critic 치명 0 / 중대 0 / 중간 2. **25th stable** — 2026-05-12 7 stable seal 누적. stable zip · build zip · release-notes

v0.1.157 — Interface Emulation P1 + 24th stable seal

v0.1.157 인터페이스 에뮬레이팅 P1 — F12 키 1회로 Photosensor + Servo Axis + Mock Modbus 통합 시연 자동 실행. Phase A 자동 어셈블리 (Photo 코일 10 / Servo 코일 11-14 + 레지스터 100 / RPM 3000 / Lead 10mm) -> Phase B 2초 전진 후 정지 (CurrentPos ≈ 1.0m) -> Phase C Home 복귀 (AxisHomedEvent). 토스트 5건 + Debug.Log 4건. spec `2026-05-12-interface-emulation.md` (380라인) 구현. **24th stable seal** — Photosensor·Servo·Emulation 모두 완성된 시연 자산. stable zip · build zip · release-notes · spec

v0.1.155 — Servo Maker Presets + 23rd stable seal

v0.1.155 서보 메이커 프리셋 3종 — Mitsubishi MR-J5 (표준 3000RPM/10Nm/10mm/Linear) · Yaskawa Sigma-X (고속 6000RPM/1.27Nm/5mm/SCurve) · Panasonic Minas A6 (범용 3000RPM/5Nm/10mm/Linear). Inspector 구동부 카드 최상단 "프리셋" DropdownField — 선택 시 ServoAxisPresets.Apply 호출 (RPM/Torque/Lead/AccelMode/AccelTime/DecelTime/SCurveRatio 일괄 + RecalcVelocityCaches 자동) -> FlashToast -> Inspector 재렌더. Photosensor PresetDropdown 패턴 재사용. **23rd stable seal** — Photosensor + Servo Axis 모듈 완전 완성. stable zip · build zip · release-notes

v0.1.154 — 서보 P2 ActuatorPlcBridge + 22nd stable seal

v0.1.154 spec §5-2 Modbus 매핑 구현. ActuatorPlcBridge MonoBehaviour 신규 — Coil 4종 (Forward/Backward/Stop/Home) rising edge 폴링 -> Command* 호출 (중복 방지 dict). Actuator.CurrentPos -> RegisterPos write (mm 정수 + 32768 shift, ushort 음수 보존). Bootstrap autoAttachMotorPlcSync 분기에서 Modbus + ActuatorDriver 전달. 양방향 sync — PLC ladder -> 서보 구동 / 서보 위치 -> PLC 모니터. Player.log "ActuatorPlcBridge 부착" 확인. **22nd stable seal** — 서보 모듈 P1+P2 완성. stable zip · build zip · release-notes

v0.1.153 — 서보 P1.2+P1.3 (ActuatorDriver + Inspector + Persistence)

v0.1.153 ActuatorDriver MonoBehaviour 신규 (매 프레임 UpdateActuator 일괄, SensorPollingDriver 와 달리 Time.deltaTime 기반 — actuator 위치 정확도). Bootstrap 자동 부착 + LoadProject Actuators 복원 + RegisterActuator 재호출. RenderActuatorBlock Inspector 카드: 타입/구동방향(LocalActuatorAxis) · RPM·정격토크·리드(서보 파라미터) · Home·RLS·FLS(위치 기준 m) · 가속 모드/시간/감속 시간 · Command 4 버튼(◀▶■⌂) · Modbus 5 매핑(Fwd/Bwd/Stop/Home/RegPos) · 4 런타임 진단(상태/현재위치/속도/MaxV). spec §4 부품당 1개 제한 — 버튼 비활성화. Player.log "ActuatorDriver 부착" 확인. zip

v0.1.152 — 서보 구동 축 P1.1 (IActuator + ServoAxisActuator 데이터/구동 로직)

v0.1.152 spec `2026-05-12-actuator-servo-axis.md` (456라인) §5+§6 구현. Actuators namespace 신규: IActuator 인터페이스 + 4 enum (ActuatorType / ActuatorState / AccelMode / LimitType) + LocalActuatorAxis. ServoAxisActuator (~180라인) — 데이터 fields (식별/방향/RPM·정격토크·리드/위치기준/가속프로파일/Modbus매핑) + Initialize · CommandForward/Backward/Stop/Home + UpdateActuator 본문 (Mathf.MoveTowards/SmoothStep · float 비교 1회 리미트 · CurrentPos m->mm 변환). 이벤트 3종 (LimitReached/AxisHomed/AxisPositionChanged) + EventBus on/publish overload. Part.Actuators 필드 (JsonUtility 자동 직렬화). 빌드 OK 18s · 컴파일 정상 · Inspector 통합은 P1.2. zip

v0.1.151 — P3.3 메이커 프리셋 + 21st stable seal

v0.1.151 PhotoSensorPresets static (OMRON E3Z 표준 100mm 30° / SICK GR 광폭 1000mm 45° / Keyence FU 수렴 700mm 10°). Inspector RenderPhotoSensorCard 최상단 "프리셋" 드롭다운 (적용 시 SensingDistance·AngleMode·SensingAngle·Delays 일괄 갱신 + 토스트). (사용자 정의) = skip 마커. 포토센서 모듈 P1+P2+P3 (9 사이클 v0.1.143~151) 전체 spec 구현 완료 -> 21st stable. stable zip · build zip · release-notes

v0.1.150 — P3.2 Modbus 코일 매핑 (SensorState -> COIL sync)

v0.1.150 spec §6 Modbus 연동 row 구현. PhotoSensorComponent.ModbusCoil int 필드 (0=미설정, 1~9999=COIL:N). SensorStateChangedEvent에 ModbusCoil 추가. SensorPlcBridge 신규 (MotorPlcSyncBridge 패턴 일관, EventBus.OnSensorStateChanged 구독 -> ModbusTcpAdapter.WriteBit). Bootstrap 부착 로그 확인. Inspector RenderPhotoSensorCard "Modbus 코일" row 추가 (Clamp 0~9999 + 토스트 "Coil:N 연결" / "해제"). zip

v0.1.149 — P3.1 SensorPersistence (JSON save/load 활성)

v0.1.149 spec §9 schema. Part.Sensors `[NonSerialized]` 해제 -> JsonUtility 자동 직렬화. ProjectFile.Save가 sensors[] 포함. Bootstrap.LoadProject 후속에 Sensors 복원 + SensorPollingDriver.RegisterSensor 재호출 분기 추가 (PhotoSensorVisualizer 자동 생성). Inspector "(저장 불가 — P3 예정)" 라벨 제거 + AddPhotoSensorToPart 토스트 단순화 ("센서 추가: SENSOR-..."). zip

v0.1.148 — P2 cleanup (디버그 CLI 제거 + spec §7 가시성 조건 완성)

v0.1.148 v0.1.147 의 `-auto-add-sensor` CLI + `_autoAddSensor` 멤버 + 처리 분기 모두 제거 (qa-real-input-only.md §1.1 "1회 override · 다음 사이클 제거" 약속 이행). spec §7 가시성 조건 완전 구현 — SensorPollingDriver.SetSelectedPart(Part) 추가 + Bootstrap RenderInspector / RenderInspectorEmptyState 에서 selection push. PhotoSensorVisualizer.Update 가 `_sensor.IsVisualized OR ownerSelected` 룰 적용 (IsVisualized OFF 라도 owner 선택 시 표시 / 미선택 시 숨김). zip

v0.1.147 — 포토센서 P2 와이어프레임 시각화 (LineRenderer cone)

v0.1.147 spec §7 시각화 구현. PhotoSensorVisualizer MonoBehaviour (~130라인) — 10 LineRenderer (중심 축선 + 외곽 8 + 선단 링 32 seg). 색상 SSOT: NO 기준 비감지 파랑(#4488FF α0.35) / 감지 초록(#44FF88 α0.55) + 펄스 alpha. NC 모드 = 반전. SensorPollingDriver.RegisterSensor 시 viz GameObject 자동 생성, UnregisterSensor 시 Destroy. 거리 spec m -> ×1000f mm 변환. 셰이더 `factory00/OutlineAlwaysOnTop` fallback (Sprites/Default 빌드 strip 회피, occlusion 회피). 두께 50mm (카메라 거리 ~8800mm 가시성). CLI `-auto-add-sensor` 1회 override (qa-real-input-only.md §1.1 예외 — v0.1.148 제거 예약) — firstMotor 자동 PhotoSensor 부착 + bounds 기반 거리 자동 조정. zip

v0.1.146 — 포토센서 critic 중대 2건 fix (단위 mm 변환 + 저장 불가 안내)

v0.1.146 critic 자가 검토 결과 중대 2건 처리: ① 단위 mismatch — spec 거리 0.01~10.0 m 입력값을 Unity Physics 호출 직전 ×1000 변환 (CLAUDE.md "내부 단위 mm 고정"과 일관). worldPos 자체가 mm scaled 좌표라 검색 반경도 mm 필요. ② NonSerialized 데이터 손실 UX 안내 — Inspector "센서" 헤더 옆 "(저장 불가 — P3 예정)" 회색 이탤릭 라벨 + tooltip ("현재 세션 안에서만 유지 / 저장 -> 재로드 시 사라짐") + AddPhotoSensorToPart 토스트 보강 ("센서 추가: ID · 저장 불가(P3 예정)"). 사용자 데이터 손실 회귀 사전 안내. zip

v0.1.145 — 포토센서 Inspector UI (+센서 추가 / 카드 위젯)

v0.1.145 spec §6 Inspector UI 구현. RenderSensorBlock(p) 추가 — 골드 헤더 "센서" + "+ 센서 추가" 버튼 / 각 센서 카드 (골드 좌측 strip + SENSOR-ID 헤더 + 삭제). 위젯 9종: 위치(Vec3 X/Y/Z 컬러) · 방향(LocalAxisDir 드롭다운) · 회전(Vec3 deg) · 거리 슬라이더(0.01~10m) · 각도모드 (Free/Convergent/Diffuse -> ResetAngleForMode) · 각도 슬라이더(mode 별 범위) · NO/NC pill 토글 · ON/OFF 딜레이(0~5000ms) · 시각화 토글. 런타임 진단: 주기/출력(ON·OFF 색상)/Raw 감지. SensorPollingDriver 멤버 캐시 -> RegisterSensor / UnregisterSensor 호출. zip

v0.1.144 — 포토센서 P1.2 (50ms 폴러 + OverlapSphere 감지 + ContactType edge trigger)

v0.1.144 SensorPollingDriver MonoBehaviour 신규 (WaitForSeconds 0.05s 코루틴). PhotoSensorComponent.UpdateSensor 본문 작성 — Physics.OverlapSphereNonAlloc(_overlapBuf[64] GC 회피) + Vector3.Angle(worldDir, toHit) 필터 + 자기 부품 제외 + ON/OFF delay 누적 + ContactType 반영 + edge trigger Publish(SensorStateChangedEvent). Bootstrap에서 자동 부착 + Initialize(Bus). zip (v0.1.145 통합)

v0.1.143 — 포토센서 P1.1 (데이터 모델 + 인프라)

v0.1.143 spec: wiki/topics/specs/2026-05-12-photosensor-direct-reflection.md. 4 enum (SensorType / LocalAxisDir / ContactType / AngleMode) + ISensor 인터페이스 + PhotoSensorComponent 데이터 필드(식별/위치/방향/감지/출력/시스템/시각화) + ComputeWorldPosition / ComputeWorldDirection / ClampAngle / ResetAngleForMode 헬퍼. SensorStateChangedEvent 추가 + EventBus.OnSensorStateChanged. Part.Sensors NonSerialized 리스트. zip (v0.1.145 통합)

v0.1.142 — 회전 기즈모 radial line 두께 확대 (0.04->0.08L)

v0.1.142 v0.1.141 radial line 두께 0.04L (~4px) 가늘어 캡처에서 안 보임 -> 0.08L (axis line 일관, ~8px) 확대. 사용자 그림 선 굵기 매칭. 빨강(X)·녹색(Y)·파랑(Z) 호 + 각 ring 양 끝(0°·90°) -> 원점 radial 6개 LineRenderer 시각 명확. zip

v0.1.141 — 회전 기즈모 radial line (원점 위치 시각화)

v0.1.141 사용자 명시 "원점 위치 추정되게 까만 선처럼 그려달라 / 색은 축 컬러로". 6 LineRenderer (3 ring × 2 end). 각 90° quarter ring 양 끝(0°·90°) -> origin radial line. 색 = AxisColors[i] (X·Y·Z 톤). hover/drag HoverColor 일관. Rotate 모드 only. zip (v0.1.142 통합)

v0.1.140 — 회전 기즈모 90도 quarter (방향성 시각화) + CLI -gizmo-rotate

v0.1.140 사용자 명시 "회전 링이 각도 따라 헷갈림. 90도짜리 잘린 도넛으로 방향성 보이도록". BuildRingMesh arcDeg=90° + DistanceRayToRingArc picking 90도 arc만 인식. ring 두께 0.15L -> 0.40L (innerR 0.70 + outerR 1.10) 명료. _gizmoScale screenSizePixels=100 — 화면 100px 일정 (카메라 거리 무관). CLI -gizmo-rotate 인자로 캡처 검증 자동화 (PostMessage G 키 미도달 우회). zip

v0.1.139 — 회전 ring 두께 확대 (90° quarter 명료성 보강)

v0.1.139 v0.1.138 90° quarter 가시 면적 1/4 감소 -> 두께 0.15L -> 0.40L (~2.7배). innerR 0.85->0.70, outerR 1.0->1.10. picking 임계도 동일. _gizmoScale 화면 100px 일정 유지 (UI 크기 불변). zip

v0.1.138 — Auto Tracking ON 기본 + 프로퍼티 부품 참조 클릭 + 회전 90° quarter

v0.1.138 3건 사용자 명시 처리. (1) autoTrackingScroll default = ON + PlayerPrefs `factory00.auto_tracking_scroll` persist + OnSelectionChanged 스크롤 통합 (외부+자체 진입 동일 경로). (2) RowWithPartRef 헬퍼 — "부모" row 클릭 -> SelectPartFromExternal (호버 골드 underline). 미래 부품 참조 row 일관 패턴. (3) 회전 ring BuildRingMesh(0.85, 1.0, 64, 0f, 90f) — 90° quarter 도넛. zip

v0.1.137 — 마우스->키보드 매핑 (좌측 panel 폭 Alt+arrow)

v0.1.137 마우스 자동화 영구 차단 환경 우회. Alt+<-/-> 10px / Alt+Shift+<-/-> 50px / Alt+Home 320 reset. send-keys-to-factory00.ps1 modifier prefix 지원 (A:/C:/S:). 단, PostMessage WM_SYSKEYDOWN VK_MENU(Alt) Unity 도달 안 됨 — Stage 2 사용자 PC fallback. (코드는 v0.1.140 zip에 포함)

v0.1.136 — critic deferred #2 fix (schedule.Execute 누적 cancel)

v0.1.136 IVisualElementScheduledItem 변수 저장 + DetachFromPanelEvent 에서 Pause() 호출 -> RenderInspector 재호출 시 stale tf 의 schedule callback 명시적 cancel. v0.1.131 critic 2회차 CONDITIONAL 중대 #2 deferred 처리. GC 압박 감소 (6×N 누적 패턴 제거). zip

v0.1.135 — 모터 테이블 가독성 (Row 패턴 일관)

v0.1.135 motor-cell + PLC tab 인라인 color 강제 (USS .motor-cell 미정의 회귀 fallback). 헤더 골드 + 셀 밝은 회색 + ellipsis + tooltip + 상태 색 override (BUSY 주황 / ALARM 빨강 / STANDBY 녹색). Row 패턴과 일관 SSOT 확장. zip

v0.1.134 — Row layout + tooltip + splitter hint (사용자 명시 3건)

v0.1.134 Row + EditableFloatRow key width 80 고정 + value flexGrow 1 (값 표시 영역 대폭 확장) · ellipsis 텍스트 hover tooltip (Row key/val + 트리뷰 항목 + detail-section-title) · left-panel splitter 골드 visual hint 강화 + tooltip zip

v0.1.133 — 좌표계 World/Local 토글 + Row 색 가독성 강화 (Unreal/Unity 레퍼런스)

v0.1.133 [월드][로컬] 토글 row 추가 (Inspector + Gizmo space sync, RuntimeGizmo.space SSOT). World: position/eulerAngles, Local: localPosition/localEulerAngles. X 단축키 토글 시 Inspector 자동 갱신. Row 색 가독성 인라인 강제 (식별자/부품 ID/부모/분류 등 USS 미적용 회귀 fallback). zip

v0.1.132 — Unreal 스타일 Transform UI (사용자 명시 5건)

v0.1.132 EditableVec3Row 재설계 — 박스 3등분 + 숫자 왼쪽 정렬 + 박스 왼쪽 "위치"/"회전각" 골드 라벨 + 박스 앞 컬러 strip (빨/녹/파) + 드래그 (colorStrip 영역) zip

v0.1.131 — Inspector Transform redesign (19번째 stable seal · v0.1.123~133 · stable archive = v0.1.133 빌드)

v0.1.131 stable Inspector Transform 위젯 (Unreal 스타일 + 좌표계 World/Local 토글) · RuntimeGizmo.space SSOT (Inspector + X 단축키 + 설정 패널 통일) · Row 색 가독성 인라인 강제 (USS 미적용 회귀 영구 fallback) · 사용자 명시 21건 (v0.1.131:12 + v0.1.132:5 + v0.1.133:4) · critic 치명 1 + 중대 4 모두 fix. stable archive zip = v0.1.133 빌드 (2회 교체) zip (131) zip (132) zip (133) stable archive (v0.1.133 빌드) release notes GitHub

v0.1.130 — Inspector Transform 위젯 (xyz 한 줄 + F1 소수점) + 폰트 축소 + 골드 톤

v0.1.130 RenderInspector 최상단 EditableVec3Row + xyz 한 줄 + F1 소수점 + 인라인 self-style + Vec3 title 골드 SSOT + critic 치명 fix zip

v0.1.129 — 프로퍼티 색 가독성 강화 (text-secondary/primary)

v0.1.129 Inspector 키/값 가독성 색 톤 강화 (v0.1.130에 통합 봉인) zip (130 통합)

v0.1.128 — 텍스트 overflow ellipsis 룰 + 정책 SSOT

v0.1.128 텍스트 overflow ellipsis 룰 + 정책 SSOT zip release notes GitHub

v0.1.127 — AxisIndicator UI 복원 (v0.1.123 USS 단독 이양 회귀 fix)

v0.1.127 AxisIndicator UI 복원 (v0.1.123 USS 단독 이양 회귀 fix) zip release notes GitHub

v0.1.126 — crosshair Tier 2 USS + stale schtasks 정리

v0.1.126 crosshair Tier 2 USS + stale schtasks 정리 zip release notes GitHub

v0.1.125 — detail-pane / drawer-body Tier 2 USS (10 inline -> token)

v0.1.125 detail-pane / drawer-body Tier 2 USS (10 inline -> token) zip release notes GitHub

v0.1.124 — left-panel Tier 2 USS 이양 (5 inline -> token 매핑)

v0.1.124 left-panel Tier 2 USS 이양 (5 inline -> token 매핑) zip release notes GitHub

v0.1.123 — AxisIndicator Tier 2 USS 이양 (inline 20 라인 -> USS class)

v0.1.123 AxisIndicator Tier 2 USS 이양 (inline 20 라인 -> USS class) zip release notes GitHub

v0.1.122 — / 검색 focus consume fix (KeyDownEvent 문자 누수 차단)

v0.1.122 / 검색 focus consume fix (KeyDownEvent 문자 누수 차단) zip release notes GitHub

v0.1.121-qa — 전수 QA 재실행 — 1920x1080 + 키보드 자동화 13/13

v0.1.121-qa 전수 QA 재실행 — 1920x1080 + 키보드 자동화 13/13 zip release notes GitHub

v0.1.120 — AxisIndicator 우하단 + Unity 캡처 표준

v0.1.120 AxisIndicator 우하단 + Unity 캡처 표준 zip release notes GitHub

v0.1.119 — Unity ScreenCapture 1920x1080 offscreen — display 제약 우회

v0.1.119 Unity ScreenCapture 1920x1080 offscreen — display 제약 우회 zip release notes GitHub

v0.1.118 — critic deferred 3건 처리 + 해상도 옵션 + 전체 캡처 1280x720

v0.1.118 critic deferred 3건 처리 + 해상도 옵션 + 전체 캡처 1280x720 zip release notes GitHub

v0.1.117 — ForceLayoutStyles Tier 1 USS 이양 + critic 치명·중대 fix

v0.1.117 ForceLayoutStyles Tier 1 USS 이양 + critic 치명·중대 fix zip release notes GitHub

v0.1.114 — 검색 placeholder '/ 부품 검색…' (단축키 hint) + ForceLayoutStyles backlog 분석

v0.1.114 검색 placeholder '/ 부품 검색…' (단축키 hint) + ForceLayoutStyles backlog 분석 zip release notes GitHub

v0.1.113 — 부품 리스트 기본 사이즈 10 row 확장 (사용자 명시)

v0.1.113 부품 리스트 기본 사이즈 10 row 확장 (사용자 명시) zip release notes GitHub

v0.1.112 — status Track:ON/OFF 표시 (모든 토글 가시화 완료)

v0.1.112 status Track:ON/OFF 표시 (모든 토글 가시화 완료) zip release notes GitHub

v0.1.111 — status BBox/Gizmo 상태 표시

v0.1.111 status BBox/Gizmo 상태 표시 zip release notes GitHub

v0.1.110 — status Lit/Unlit 표시

v0.1.110 status Lit/Unlit 표시 zip release notes GitHub

v0.1.109 — Lit default ON + 15번째 stable 봉인

v0.1.109 Lit default ON + 15번째 stable 봉인 zip release notes GitHub

v0.1.108 — Lit SSOT PlayerPrefs 통일 (critic 치명 #1)

v0.1.108 Lit SSOT PlayerPrefs 통일 (critic 치명 #1) zip release notes GitHub

v0.1.107 — Shift+R 디버그 키 제거

v0.1.107 Shift+R 디버그 키 제거 zip release notes GitHub
<- 메인