focused='cmd-open' Blur+flag IsAnyUIFocused=True. cmd-open(불러오기 버튼)이 IsLnbElementFocused 화이트리스트(_lnbCmds Contains)에 누락 — v0.1.551 _lnbTabs 만 추가→_lnbCmds 누락 재발. critic 자체검증과 PM 실측 불일치.[alt] downTime Ldn=True 6건), v0.1.551 미touch._cameraFocusRestorePending true + 메뉴 닫힘 + 텍스트입력 아님 → 카메라 통과(어느 element focus 든).[alt]/focusedElement 진단 로그 유지 (PM regression-diagnosis §0순위).Assets/Scripts/Game/Factory00Bootstrap.cs — IsAnyUIFocused 플래그 우선 판정 + IsLnbElementFocused 제거 + Alt 감지 camKeyHeldForAlt 가드

_focusDummy.Focus() 후 IsAnyUIFocused()=True → Focus() 가 focus 를 실제로 안 옮김. v0.1.550 내 fix(_focusDummy.Focus() 추가) 무효._cameraFocusRestorePending 플래그: 메뉴 명령 클릭/viewport 클릭/불러오기(카메라 복귀 의도) set, Tab 순회/메뉴 열림(ShowLnbDropdown) clear.IsAnyUIFocused(): 플래그 true + 메뉴 닫힘(_lnbActiveIdx<0) + lnb element focus = 카메라 통과. Tab 헤더 focus 는 플래그 false → 차단 유지(focus-key-isolation 양립).Assets/Scripts/Game/Factory00Bootstrap.cs — IsAnyUIFocused/IsLnbElementFocused + HideLnbDropdown/OpenTwn 플래그 set + Tab/ShowLnbDropdown clear + 진단 로그(focusedElement name, PM report-0050)
HideLnbDropdown(bool restoreCameraFocus) 파라미터 추가 — 메뉴 명령/viewport 클릭으로 닫을 때 _focusDummy 로 focus 복원IsAnyUIFocused()=true 영구 → 카메라 입력(WASD/휠/Space/C) 전면 차단Assets/Scripts/Game/Factory00Bootstrap.cs — HideLnbDropdown 시그니처 + L1823(메뉴 명령 클릭 true) + L4746(viewport 클릭 true)
name#siblingIndex 로 id 생성 — 단일 import 내에서만 unique. ImportGlbAsync 가 BuildParts(root.transform) 를 idPrefix="" 기본값으로 호출 → 같은 도면 재import 시 root=new GameObject(fileName)(동일 fileName) → 부모 Part id 충돌. 증상 1=Parts.AddRange 중복 등록 / 증상 2=같은 parentId 로 자식 묶여 부모 선택 시 전체 동조.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
camCtrl.IsTextInputFocused(L439)=IsAnyUIFocused 가드로 WASD/C/Space/휠/orbit 카메라 입력 전면 차단(휠 포함 = PM 추정 확정). L529 _focusDummy startup 고착 동종 이력._focusDummy.Focus() — IsAnyUIFocused()=false(L531 제외) + polling 재 focus 대상과 일관. focus 고착 element 무관 해제. 주의: _viewportFocusAnchor 는 IsAnyUIFocused 제외 목록(L518~535)에 없어 Focus 시 true → 카메라 차단 유지 = 함정. _focusDummy 가 정답.Debug.Log [QA-136] IsAnyUIFocused=false 로 Player.log 검증 가능.Assets/Scripts/Game/Factory00Bootstrap.cs — OpenTwnPath 완료 시 _focusDummy.Focus() + 진단 로그(+8라인)
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 호출
FloatingSubWindows() 공통 순회. 신규 floating 패널은 본 메서드 1줄 등록으로 자동 안전망(모듈화 단일 지점, "문제 발생 코드만 분리" 원칙).Assets/Scripts/Game/Factory00Bootstrap.cs — IsPointerOverUI 순회 교체 + FloatingSubWindows() 헬퍼 신규(+12라인)
!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).Assets/Scripts/Game/Factory00Bootstrap.cs — IsPointerOverUI geometry 폴백 +6라인
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (X 닫기 버튼)Assets/Scripts/Game/Factory00Bootstrap.cs (ESC cascade PLC 분기 + 주석)
Assets/Scripts/Game/Factory00MaterialGenerator.cs (CreateBaseUnlit _Cull=0 무조건 + doubleSided 분기 제거)
evt.target is Button 가드 — Refresh/모드 버튼 클릭은 창 이동 안 함. title Label 등 비-Button 영역은 드래그 허용._root.Clear() 시한폭탄): 제거. Build 1회 + 빈 _root 라 잉여 + 미래 재호출 시 리사이즈 핸들 삭제 위험 차단.Assets/Scripts/UI/ResizableWindowController.cs (WireMove 버튼 가드)Assets/Scripts/Communication/Modbus/ModbusTcpInspectorPanel.cs (Clear 제거)Assets/Scripts/Communication/Mitsubishi/MitsubishiPlcDriverPanel.cs (Clear 제거)
Assets/Scripts/Plc/PlcAddressMappingPanel.csAssets/Scripts/Communication/Modbus/SignalSimulatorPanel.csAssets/Scripts/Communication/Modbus/ModbusTcpInspectorPanel.csAssets/Scripts/Communication/Mitsubishi/MitsubishiPlcDriverPanel.cs
Assets/Scripts/Communication/Modbus/ModbusAddressMappingPanel.cs (IResizableWindow + 2층 분리 + Attach)Assets/Scripts/UI/{SubWindowLayout,SubWindowLayoutStore,ResizableWindowController}.cs, Events/SubWindowEvents.cs
Assets/Scripts/Plc/PlcAddressMappingPanel.csAssets/Scripts/Communication/Modbus/ModbusAddressMappingPanel.csAssets/Scripts/Communication/Modbus/SignalSimulatorPanel.csAssets/Scripts/Communication/Modbus/ModbusTcpInspectorPanel.csAssets/Scripts/Communication/Mitsubishi/MitsubishiPlcDriverPanel.cs
Assets/Scripts/Game/Factory00Bootstrap.cs (IsInspectorTextInputFocused / IsAnyTextFieldFocused — ancestry 포괄)
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)Assets/Scripts/Actuators/ServoAxisVisualizer.csAssets/Scripts/Actuators/ActuatorDriver.cs (서보 visualizer 등록/정리)
SensorReadonlyRowRef(value Label 참조 반환) + card.schedule.Execute(...).Every(100)로 상태/현재위치/현재속도 텍스트만 매 100ms 갱신. 카드 panel 떠나면 자동 중단, 입력필드 destroy 부작용 0. PLC 비의존(수동/데모 구동)Assets/Scripts/Game/Factory00Bootstrap.cs (SensorReadonlyRowRef 헬퍼 + RenderServoAxisCard 모니터링 schedule 갱신)
Assets/Scripts/Game/Factory00Bootstrap.cs (ApplyTwnPayloadCore 매칭 루프 SetActive 복원)
.pre-S0048.bak.twn 확장자가 .twn → 파일피커(*.twn) 노출 → JP가 마이그레이션 전 스냅샷 오픈 → TowerLamp(post-backup) 미복구. 백업 비-멱등(.bak.twn.bak.twn 누적). 폴더 오염.pre-S0048.bak(.twn 아님 → *.twn 피커 미노출, JP 오픈 차단)path.Contains(".pre-S0048.bak")면 재백업 skip (.bak.bak 누적 차단).pre-S0048.bak.twn 자동 rename → .pre-S0048.bak (피커 오염 + 폴더 정리. 신 백업 있으면 옛것 삭제)Assets/Scripts/Game/Factory00Bootstrap.cs (OpenTwnPath 백업 로직)
_altDownTime false positive → 키보드 공백 구간(otherKey 없음)에서 Alt keyup → 메뉴바 발동Input.anyKeyDown(기존 otherKey 검사)은 새 keydown만 잡아 우클릭 회전 중 held 마우스를 누락 → Alt window 중 마우스 버튼 held면 otherKey=true (메뉴바 차단)Assets/Scripts/Game/Factory00Bootstrap.cs (Alt 메뉴바 detect path 3곳 — 가드 + 로그)
Assets/Scripts/Plc/ConfirmModal.cs (Build idempotent)Assets/Scripts/Plc/PlcAddressMappingPanel.cs (Hide/Show 모달 정리 + IsVisible 가드)Assets/Scripts/Plc/PlcAddressAssigner.cs (충돌 메시지 정리)
ConfirmModal — 재사용 확인 모달(전체화면 backdrop + 중앙 다이얼로그 + 확인/취소). 순수 UI Toolkit, 도메인 무참조(격리 모듈)PlcAddressAssigner.AssignManual → ManualOutcome enum(Ok/Rejected/Conflict) + suggested(다음 빈 주소) 반환. 충돌과 무효 구분Assets/Scripts/Plc/ConfirmModal.csPlcAddressAssigner.cs(ManualOutcome enum+suggested), PlcAddressMappingPanel.cs(_modal+라우팅+ResolveConflict)
PlcTowerLampAssigner base+offset 격리 모듈 — 자동(연속 빈 블록)+수동(블록 충돌). ModbusCoilBase SSOT 역기록Assets/Scripts/Plc/PlcAddressMigration.cs (Apply TowerLamp case + 중복 제거)Assets/Scripts/Plc/PlcTowerLampAssigner.cs (HashSet 호이스팅 + 제거)Assets/Scripts/Plc/{PlcAddressMappingPanel,IAddressableComponent}.cs (제거)
PlcTowerLampAssigner — TowerLamp base+offset(Ch0=base, Ch1+=base+i 연속 Coil 블록) 특수 할당CanAssignPort(comp, port) — TowerLamp는 Ch0(base)만 할당, Ch1+는 파생 표시. 일반 포트는 전부Assets/Scripts/Plc/PlcTowerLampAssigner.csPlcAddressAssigner.cs(CanAssignPort+방어), PlcAddressMappingPanel.cs(라우팅+파생 라벨)
PlcAddressAssigner UnityEngine 무참조화 — Time.realtimeSinceStartupAsDouble를 뷰(Panel)가 주입 (AssignAuto/AssignManual/Write에 double ts 인자)_modeBtn 제거 (지역 modeBtn 클로저로 충분)PlcTabClassifier(분류 SSOT) / PlcAddressAssigner(할당 write — UI·엔진 무참조 순수 서비스) / PortDragController(드래그) / PlcAddressMappingPanel(뷰)Assets/Scripts/Plc/PlcAddressAssigner.cs (ts 주입 + UnityEngine using 제거)Assets/Scripts/Plc/PlcAddressMappingPanel.cs (ts 전달 + _modeBtn 제거)
PlcTabClassifier(61) — device↔탭↔포트타입 매핑 SSOT (분류 버그 격리)PlcAddressAssigner(88) — 할당 SSOT write(Set+Apply 역기록+발행), 충돌/빈주소 (영속 버그 격리, UI 무참조)PortDragController(82) — 드래그 5-핸들러+capture 가드+panel.Pick (드래그 버그 격리)PlcAddressMappingPanel(274) — 렌더링+입력 wiring(뷰)만Assets/Scripts/Plc/{PlcTabClassifier,PlcAddressAssigner,PortDragController}.csAssets/Scripts/Plc/PlcAddressMappingPanel.cs (425→274, 뷰만)
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (모드 토글 + 수동 IntegerField + ManualAssign 재진입/충돌 가드)
Assets/Scripts/Plc/PlcAddressMappingPanel.cs (모드 토글 + 수동 IntegerField 분기 + ManualAssign/IsNumberUsed/CurNumber)
PlcAddressMigration.Apply(5종, Register 거울상) → 옛 필드 write(옛 필드 SSOT, 다음 로드 재생산, 소실 0)Assets/Scripts/Plc/PlcAddressMappingPanel.cs (드래그+좌측+할당 + critic 2-pass fix)Assets/Scripts/Plc/PlcAddressMigration.cs (Apply 역기록)Assets/Scripts/Game/Factory00Bootstrap.cs (wiring + box-select 가드)
PlcAddressMigration.Apply(5종, Register 거울상) → 옛 필드 write(옛 필드 SSOT, 다음 로드 재생산)Assets/Scripts/Plc/PlcAddressMappingPanel.cs (드래그+좌측+할당 + critic fix)Assets/Scripts/Plc/PlcAddressMigration.cs (Apply 역기록)Assets/Scripts/Game/Factory00Bootstrap.cs (wiring + box-select 가드)
PlcAddressMigration.Apply(Register 거울상, 5종) → 옛 필드 write → 다음 로드 populate 재생산(소실 0, 옛 필드 SSOT)AddressMappingChangedEvent 발행 + 자동 연속 할당(1부터, device별 빈 슬롯)Assets/Scripts/Plc/PlcAddressMappingPanel.cs (드래그 + 좌측 포트행 + 할당 재작성)Assets/Scripts/Plc/PlcAddressMigration.cs (Apply 역기록 writer +52라인)Assets/Scripts/Game/Factory00Bootstrap.cs (OnDragStateChanged/OnToast wiring + box-select 가드)
PlcAddressMappingPanel 4탭 PLC 어드레스 매핑 에디터 (출력/입력/데이터출력/데이터입력) — 컴포넌트 Inspector "통신 어드레스 설정" 버튼이 여는 표시 UI_plcAddressMap(SSOT) 조회. classifyTab = Device→탭OpenAddressMappingEditorEvent 구독 → lazy build + Show. 명명 핸들러 → OnDestroy 해제Assets/Scripts/Plc/PlcAddressMappingPanel.cs (신규)Assets/Scripts/Game/Factory00Bootstrap.cs (필드 + Awake 구독 + 명명 핸들러 + OnDestroy 해제 + 구식버튼 Hide)
PlcAddressMappingPanel — 컴포넌트 Inspector "통신 어드레스 설정" 버튼이 여는 4탭 에디터 (출력/입력/데이터출력/데이터입력)_plcAddressMap(SSOT) 조회OpenAddressMappingEditorEvent 구독 (C5 설정 버튼 발행) → lazy build + Show. 명명 핸들러 → OnDestroy 해제Assets/Scripts/Plc/PlcAddressMappingPanel.cs (신규 193라인)Assets/Scripts/Game/Factory00Bootstrap.cs (필드 + Awake 구독 + 명명 핸들러 + OnDestroy 해제 ~22라인)
OpenAddressMappingEditorEvent 발행 (에디터 구독 S0012/S0049는 C6 후속 — 현재 토스트만)RenderAddressSection(card, comp) 1개 + 6 카드(Servo/Rotary/Pneumatic×2/PhotoSensor/TowerLamp) 호출PlcAddressMigration.Register 즉석 호출 → 라이브 옛 필드값 반영(stale 회피)Assets/Scripts/Game/Factory00Bootstrap.cs (RenderAddressSection 헬퍼 + 6 카드 1줄씩)
PlcAddressMap 등록 (런타임 shadow). @Obsolete 병존 — 옛 필드 active 유지PlcAddressMigration 중앙 클래스 (6 컴포넌트 포트→옛필드 매핑, value=0 skip)_plcAddressMap 필드 + PopulatePlcAddressMapFromLegacyFields()(로드 후 1패스) + .twn 1회 백업(.pre-S0048.bak.twn, idempotent)Assets/Scripts/Plc/PlcAddressMigration.cs (신규)Assets/Scripts/Game/Factory00Bootstrap.cs (_plcAddressMap + Populate + 백업 + 호출)
IAddressableComponent + PlcPortDefinition + PortDirection/PortDataType (Factory00.Plc)Assets/Scripts/Plc/IAddressableComponent.cs (신규)Assets/Scripts/Actuators/{ServoAxis,Rotary,PneumaticCylinder,PneumaticRotaryCylinder}Actuator.cs + Sensors/PhotoSensorComponent.cs + Outputs/TowerLampComponent.cs
OpenAddressMappingEditorEvent(AddressMappingContext) / AddressMappingChangedEvent(IPlcAddress Old/New) / ProtocolChangedEvent / PortSignalChangedEventAssets/Scripts/Events/PlcAddressEvents.cs (신규) + EventBus.cs (3곳 등록)
SubWindowLayoutChangedEvent/ResetEvent 발행 + 오픈 시 복원onDragStateChanged 콜백 decouple. 커서 전환 P3.Assets/Scripts/UI/ResizableWindowController.cs (신규 205라인)
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 (신규)ResizableWindowController 드래그+8핸들 리사이즈+클램프, 복잡)는 다음 focused 사이클(full critic).
IPlcAddress(protocol 추상) + PlcProtocol enum + PortKey(ComponentId,PortName) struct + PlcAddressMap(Dictionary SSOT + 역방향 조회 + Protocol 캡슐화) + ModbusPlcAddress(IPlcAddress 구현)ModbusAddress가 기존 live Factory00.Plc.ModbusAddress(ModbusTcpAdapter, 9파일 참조)와 충돌 → ModbusPlcAddress 리네임 fix{get; private set;} + SetProtocol(변경 시 매핑 초기화) 캡슐화Assets/Scripts/Plc/IPlcAddress.cs + PlcAddressMap.cs (신규)Assets/Scripts/Communication/Modbus/ModbusPlcAddress.cs (신규)
BuildBatchReadWord(0xA8,100,5) byte 단위 일치Assets/Scripts/Communication/Mitsubishi/McProtocol/*.cs (8 신규)Tools/McProtocol/McGoldenTest.cs + run-golden.sh (골든 standalone 검증 SSOT)
AutoLaunchBridge(default false) + LaunchBridge() — UseMock=false + AutoLaunchBridge 시 factory00.exe 옆 MxBridge/MxBridge.exe 자동 실행. Stop 시 kill.IsBridgeRunning() TCP 체크 → orphan/수동 브리지 재사용(중복 spawn / port 충돌 회피, critic 중대 #1·#2).mxbridge.log 파일 출력(CreateNoWindow auto-launch 진단 경로, critic 중대 #3).Assets/Scripts/Communication/Mitsubishi/MitsubishiPlcDriverComponent.cs — AutoLaunchBridge + LaunchBridge + IsBridgeRunningTools/MxBridge/MxBridge.cs — Log 파일 출력
Tools/MxBridge/MxBridge.cs (신규 호스트) + Tools/MxBridge/build-mxbridge.shBuilds/Win64/MxBridge/ (배포 번들)
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.Assets/Scripts/Game/Factory00Bootstrap.cs — SensorFloatField/SensorSliderRow 파라미터 undo (ComponentEditCommand 재사용)
Assets/Scripts/Game/Factory00Bootstrap.cs — Alt 2-state 메뉴 모드 라우팅 + 최근 프로젝트 hover submenu
effOn = (NC)? !FinalOutput : FinalOutput — 딜레이+ContactType 반영된 FinalOutput 기반.RawDetected) 즉시 기반으로 교체. SensorVisualizationData 에 RawDetected 추가 + GetGizmoData 설정 + visualizer effOn = d.RawDetected.Assets/Scripts/Sensors/ISensor.cs — SensorVisualizationData.RawDetectedAssets/Scripts/Sensors/PhotoSensorComponent.cs — GetGizmoData RawDetectedAssets/Scripts/Sensors/PhotoSensorVisualizer.cs — effOn = d.RawDetected
Assets/UI/Components/Ribbon.uxml — 뷰 메뉴 단축키 라벨 (F4/F5~F8)Assets/Scripts/Game/Factory00Bootstrap.cs — MakeBtn 시인성 + hover
CameraViewController.Update 의 mode dispatch switch 누락 → _mode=Back/Left/Bottom 일 때 UpdateOrbit/UpdateFirstPerson 어느 것도 미호출 → 카메라 입력 핸들러 dead.SetLitMode(_litMode) 호출 → Lit ON 이면 SwapToLitShader 로 재임포트 mat 도 Lit 동기화 (흰색 해소 유지 + Lit 상태 정합).Assets/Scripts/Game/CameraViewController.cs — Update dispatch Back/Left/Bottom → UpdateOrbitAssets/Scripts/Game/Factory00Bootstrap.cs — Open 재임포트 후 SetLitMode(_litMode)
BringToFront() 보유하나, 두 번째 서브창(L9115)은 root.Add 후 BringToFront 누락 → hud-root/메뉴바 BringToFront 후 그 뒤에 숨김.root.Add 직후 BringToFront() 추가 (첫 서브창 미러). 모달 overlay 항상 최상위.Assets/Scripts/Game/Factory00Bootstrap.cs — 두 번째 서브창 BringToFront 추가
MouseDownEvent 사용 → UI Toolkit 6 에서 씬 영역(카메라 렌더 위) backdrop 클릭에 불안정 발화.MouseDownEvent (레거시) → 씬 영역 클릭 시 미발화. raw-input 3D pick 은 모달 overUI=true 로 이미 skip → 결과적으로 씬 클릭이 아무 동작 안 함(서브창 유지).MouseDownEvent → PointerDownEvent (M-01 다이얼로그 동일 패턴, UI Toolkit 6 신뢰). pickingMode=Position 전체 영역 backdrop → 씬/SNB 어디 클릭이든 닫기.Assets/Scripts/Game/Factory00Bootstrap.cs — 서브창 backdrop MouseDownEvent → PointerDownEvent (2곳)
Assets/Scripts/Game/Factory00Bootstrap.cs — 씬 컨텍스트 메뉴 뷰 서브메뉴 항목 리본 정합
IsInspectorTextInputFocused() 신규 — _detailPane 안 TextField/FloatField/IntegerField/DoubleField focus 검출. 5개 값-변경 re-render 호출처에 가드 추가 → 텍스트 입력 편집 중 re-render skip(모델은 갱신, 시각 rebuild만 blur 후 지연). 토글/드롭다운/선택변경은 텍스트필드 미focus라 정상 렌더.Assets/Scripts/Game/Factory00Bootstrap.cs — IsInspectorTextInputFocused 헬퍼 + 값-변경 re-render 5곳 가드
Factory00MaterialGenerator(URP/Unlit, 조명 무관, glb baseColor 정확). 그러나 프로젝트 Open 재임포트(L3109)는 StepImportService.ImportGlbAsync → 내부 ApplyShaderFallback(URP/Simple Lit 교체). Simple Lit는 조명 반응 → 씬 조명 부재/오류 시 전체 흰색 over-render. QC 로그 [step-import] shader fallback 4371 mat 이 증거.ImportGlbAsync 에 useMaterialGenerator 파라미터 추가. Open 재임포트는 true → 초기-로드와 동일한 Factory00MaterialGenerator(URP/Unlit) + Simple Lit fallback skip. STEP 메뉴 임포트는 default false 유지(Stage 2 검증된 동작 보존).Assets/Scripts/Importers/StepImportService.cs — ImportGlbAsync useMaterialGenerator 파라미터 + ApplyShaderFallback 조건부 skipAssets/Scripts/Game/Factory00Bootstrap.cs — Open 재임포트 useMaterialGenerator:true
GetCam() = Camera.main.GetComponent() . 그러나 controller 는 별도 GameObject("CameraViewController", Bootstrap L401 신규 생성)에 부착 → Camera.main 에 없음 → GetCam() = null → 리본 뷰 메뉴 GetCam()?.ApplyMode no-op. F5~F8 은 controller 자체 Update 폴링이라 동작. GetCamCtrl()(컨텍스트 메뉴용)은 FindObjectOfType 라 정상 — 두 accessor 불일치가 증거._camCtrlRef 필드 캐시(find/create 직후 L406). GetCam() = 캐시 우선 + FindObjectOfType fallback. GetCamCtrl() → GetCam() 통합(DRY 단일 소스).Assets/Scripts/Game/Factory00Bootstrap.cs — _camCtrlRef 필드 캐시 + GetCam/GetCamCtrl 통합
Application.wantsToQuit 가로채기로 dirty 시 확인 팝업 + 종료 보류._forceQuit 플래그 — AppQuitCommandEvent 구독자가 종료 직전 true 설정 → wantsToQuit 항상 통과. 메뉴 확정 종료·autoQA capture 종료 모두 이벤트 경유 → 통과 보장. X 버튼만 _forceQuit=false 로 dialog 발동 (OS close 는 이벤트 미경유). loop 차단(저장안함→AppQuitCommandEvent→_forceQuit=true→재종료 통과).#if !UNITY_EDITOR): Editor play-mode-exit 충돌 회피. standalone 빌드만 X 버튼 가로채기. OnDestroy 에서 핸들러 해제.Assets/Scripts/Game/Factory00Bootstrap.cs — _forceQuit 필드 + AppQuitCommandEvent 구독자 _forceQuit 설정 + wantsToQuit 등록/OnWantsToQuit/OnDestroy 해제
IsDirty = 저장 시점 top 커맨드 vs 현재 top 참조 비교. undo로 저장 시점까지 되돌리면 자동 clean. 저장/신규/로드 시 MarkSaved() 호출.Assets/Scripts/Game/UndoStack.cs — IsDirty/MarkSaved/_cleanMarker + Clear 리셋Assets/Scripts/Game/Factory00Bootstrap.cs — RequestQuit/ShowQuitConfirmDialog/CloseQuitDialog + SaveCurrentProject 추출 + MarkSaved 3곳 + cmd-quit 배선 + ESC cascade 가드
Assets/UI/Components/Ribbon.uxml — cmd-recent 라벨 ▶ 인디케이터 추가
NavigationSubmitEvent.SendEvent → 무동작(focus-tab-navigation cap 학습: UI Toolkit Navigation*Event SendEvent 실효 X).ShowLnbDropdown(idx) + _lnbTabs[idx].Focus() 로 전환 (Alt-단독 활성화·키보드 메뉴 순회가 쓰는 동일 path). idx = kRibbonTabs 순서. rootEl.Q 쿼리 제거 + 캐시 _lnbTabs 사용._altOtherKey=true(기존 anyKeyDown detect)로 Alt-단독 메뉴바 활성화 차단됨. 단일 키 T/H 핸들러는 이미 Alt 가드 보유, F/E/V/R/C 충돌 없음.Assets/Scripts/Game/Factory00Bootstrap.cs — Alt+mnemonic 블록 NavigationSubmitEvent → ShowLnbDropdown 직접 호출 전환
AddComponentCommand): do/undo 페어 액션을 받는 단일 커맨드로 일반화 (DRY). 추가 = do:add/undo:remove, 삭제 = do:remove/undo:동일 인스턴스 복원.ReapplyLamp(id) => ApplyEmission(id) — 삭제 undo(또는 add redo) 시 lamp 재추가 후 material 강제 재생성 (InvalidateLamp 역연산). static ON lamp 도 즉시 복원 (update 루프는 blink 만 처리)._suppressAddRebuild 가드 우회(inline Rebuild) → Undo 도 Refresh() 경유로 통일 (가드 일관 적용 + DRY).Assets/Scripts/Game/Factory00Bootstrap.cs — ComponentEditCommand 일반화(Undo→Refresh DRY) + 6 Add rename + 6 Remove wrap + TowerLamp Add wrapAssets/Scripts/Outputs/TowerLampEmissionDriver.cs — public ReapplyLamp(string) 신규
SensorStateChangedEvent 단일 사슬이라 씬 검출 이벤트 자체가 딜레이됨.SensorDetectedEvent 신규 — Raw 감지 edge 변화 시 딜레이 무관 즉시 발행. 씬 시각화·인디케이터·디버그 구독용.SensorStateChangedEvent 유지 — FinalOutput edge(딜레이+ContactType 반영 후). PLC 출력용._lastPublishedRaw edge 비교로 즉시 발행. 초기 raw=false 정합으로 시작 spurious 이벤트 없음.Timestamp 대신 코드베이스 형제 이벤트(SensorStateChangedEvent) 컨벤션 TimestampSec 채택(내부 일관성 우선). 구독 코드는 factory00 내부 작성이므로 영향 없음.Assets/Scripts/Events/SensorDetectedEvent.cs — 신규 이벤트 struct (SensorId/PartId/RawValue/TimestampSec)Assets/Scripts/Events/EventBus.cs — OnSensorDetected event + Publish overload + Reset nullAssets/Scripts/Sensors/PhotoSensorComponent.cs — _lastPublishedRaw 필드 + Initialize + UpdateSensor 즉시 발행Assets/Scripts/Sensors/ISensor.cs — doc 주석 (이벤트 2종 분리 명시)
DeleteSelectedPart 가 3D click handler drag-state(_isDragSelecting/_lmbDownPos/_lmbDownFrame/_inspectorDragLock)를 reset 안 함. Cut(CutSelected)은 v0.1.416 에서 자체 reset 하나 직접 Delete(키/버튼) 경로는 누락. fix = DeleteSelectedPart 에 동일 reset 추가 (Cut/Delete 정합).Assets/Scripts/Game/Factory00Bootstrap.cs — DeleteSelectedPart drag-state reset.
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 패턴 미러.ActuatorDriver.RegisterActuator / SensorPollingDriver.RegisterSensor 가 _actuators/_sensors.Add 무방어 → if (Contains) return; dup 가드 추가 (Undo/Redo 재등록 시 2배 발화/유령 차단)._part.cachedTransform 파괴 → RenderInspector NRE. _part.cachedTransform != null Unity-null 가드 추가.Assets/Scripts/Game/Factory00Bootstrap.cs — AddComponentCommand + 5 헬퍼 wrap.Assets/Scripts/Actuators/ActuatorDriver.cs · Assets/Scripts/Sensors/SensorPollingDriver.cs — dup 가드.
tool-move-part 버튼 + 코드 BindRibbonCommandPlaceholder 양쪽 제거 (deprecated-spec-marking 룰 정합).review-measure(측정 로직, v0.1.346) / review-angle(L2526) / review-collision(L2556) cmds-tools 버튼에 clicked 바인딩 존재, 중복 0. PM v0.1.366 보고 stale → 종결 가능.present-screenshot(ScreenCapture) / present-scenario-play(RunInterfaceEmulationDemo) 바인딩 존재. 종결 가능.view-fit) 기wired. 종결 가능.Assets/UI/Components/Ribbon.uxml — tool-move-part 버튼 제거.Assets/Scripts/Game/Factory00Bootstrap.cs — tool-move-part placeholder bind 제거.
SetPresetView(yaw,pitch) 호출 — 내부에서 _orbitYawPitch 설정 후 ApplyMode(CameraViewMode.Default)(perspective)로 우회 → 프리셋 무동작 (QA-014 v0.1.391~413 반복 실패). F5~F8 은 ApplyMode(CameraViewMode.Front/Right/Top/Iso) 직접 호출 → 동작.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.Assets/Scripts/Game/CameraViewController.cs — enum Back/Left/Bottom + ApplyMode 3 case.Assets/Scripts/Game/Factory00Bootstrap.cs — 뷰 메뉴 7항목 SetPresetView → ApplyMode.
Input.GetKeyDown(Tab) 이중 mover. v0.1.482 가 outline-0 회피 위해 Next/Previous 통과시킨 게 원인.if (_focusDummy==null) 가드로 이미 fix → 본 차단으로 회귀 안 함 예상.Assets/Scripts/Game/Factory00Bootstrap.cs — NavigationMoveEvent 전체 차단 + FocusIn 1px no-fill.
.twn 스키마에 stepSourcePath만 있고 glb 경로 없음. Save 는 _lastStepPath(STEP 임포트 시만 설정)만 저장 → 기본 factory 씬(번들 glb 기반, STEP 임포트 안 함)은 stepSourcePath="" → Open 시 needAutoImport=false → 재임포트 안 됨 → 빈 씬 → [file-open] applied 0/8763 parts. PM repro "factory00-project.twn" 이 정확히 이 케이스.OpenTwnPath 자동 재임포트 조건 확장 — stepSourcePath 비었으면 ResolveGlbPath()(기본 번들 glb) 직접 재임포트 fallback (STEP 변환 skip). 기존 index-order id remap + ApplyTwnPayload 재사용. STEP 기반 프로젝트는 기존 경로 유지.Assets/Scripts/Game/Factory00Bootstrap.cs — OpenTwnPath 재임포트 조건 + glb fallback.
SensorVec3Field(PhotoSensor 카드 위치/회전)가 scrub 없는 Vector3FieldElement(AxisFieldElement = 키인 only) 대신 3개 AxisFieldScrubElement(드래그 scrub) 사용 — Inspector P3 EditableVec3Row 패턴 미러. 위치/회전 모두 드래그 scrub 활성화.col.bounds.center 각도만 봐서 큰 오브젝트 edge 가 cone 안이어도 center 가 축에 와야 감지. center 체크 보존 + collider AABB closest-point 체크 추가(OR) — object edge 가 cone 닿으면 감지. axisProj>0 가드로 전면 반구만 (뒤쪽 over-detection 차단, 직접반사형 spec 정합).axisProj>0 가드로 해소. 중대 #1(working struct) = RenderInspector 카드 재생성으로 비결함(P3 패턴 동일). 치명 0.Assets/Scripts/Game/Factory00Bootstrap.cs — SensorVec3Field AxisFieldScrubElement 전환.Assets/Scripts/Sensors/PhotoSensorComponent.cs — UpdateSensor closest-point 감지.
ForceLayoutStyles(L1573+L4885 다회 호출) 내부에 가드 없이 있어 매 호출마다 신규 생성 + root.Add → child[6]/[7] NaN 중복 + 콜백 누적. if (_focusDummy == null) 가드로 1회만 생성 (바로 아래 settings-VM idempotent 가드 패턴 미러).[alt] downTime set / [alt] otherKey=true / [alt] lnbTabs[0].Focus() 호출 3종 + [focus-dummy] 1회 생성 가드 통과 로그 추가. 다음 QC 에서 WASD 기동 시 [alt] lnbTabs[0].Focus() 발화 여부로 Alt 회기 확정._altDownTime=-1 stale 가드라 Alt-up 분기 미발화 분석 — 중복이 매개 가능성 우선).[alt]/[focus-dummy] 로그 분석으로 root cause 확정.Assets/Scripts/Game/Factory00Bootstrap.cs — focus-dummy 가드 (L4045) + Alt 진단 로그 3종.
AddPhotoSensorToPart에 Count >= 1 가드 추가 (구동부/타워램프 패턴 정합). Inspector "+ 센서 추가" 직접 호출 경로까지 차단. spec §3 단일 부착.SensorSliderRow에 editable 파라미터 추가 → SensingDistance만 read-only Label → 양방향 FloatField(slider↔field 동기 + min/max clamp + SetValueWithoutNotify 루프 차단). 나머지 8개 슬라이더는 기존 유지.RecomputeFinalOutput()(internal)로 추출. ContactType 토글 시 즉시 재계산 + Inspector 재렌더(Button.clicked dispatch 완료 후 schedule.Execute defer — orphan 위험 차단).schedule.Execute defer로 해소 + RecomputeFinalOutput internal 강등. 치명 0.PhotoSensorVisualizer.Update가 매 프레임 IsVisualized || ownerSelected 평가. 선택 중 ray 유지는 spec §7 정합. PM 명확화 요청 (선택 해제 후 재확인).bounds.center 기준 → cone edge 미감지. closest-point geometry 수정 (moderate).Assets/Scripts/Game/Factory00Bootstrap.cs — R-1 가드 / R-2 editable / R-6 토글 defer.Assets/Scripts/Sensors/PhotoSensorComponent.cs — R-6 RecomputeFinalOutput 추출.
RebuildVisibleParts 가 모든 부품마다 IsPartVisible 호출 + IsPartVisible 이 조상 체인마다 전체 Parts 선형 스캔 → O(N²×depth). 8763 부품 씬에서 컴포넌트 Add 직후 다초 freeze → OS 클릭 큐잉 풀림 → 엉뚱한 오브젝트에 센서 마구 추가(stray attach). freeze 가 두 증상의 공통 원인._partById 신설 → IsPartVisible / EnsureVisibleAncestors / GetPart 의 Parts 선형 스캔 제거. RebuildVisibleParts O(N²×depth) → O(N×depth) (약 4자릿수 단축). freeze 소멸 → 큐잉/stray attach 동시 해소._suppressAddRebuild). 6개 Add 핸들러 일관.ModbusTcpAdapter.Connect 가 mock skeleton(IsConnected=true + 로그)이라 블로킹 아님 — Add freeze 원인 아님.Assets/Scripts/Game/Factory00Bootstrap.cs — _partById SSOT 사전 + Add rebuild coalesce + 디바운스 가드.
NavigationMoveEvent.Direction.Next/Previous 발화. 본 callback 안 Tab navigation 까지 차단 → UI Toolkit focus controller 내부 state 불일치 → Bootstrap.Update polling Focus() 호출과 race.direction == Next/Previous (Tab/Shift+Tab) 만 통과



.claude/rules/no-keyboard-sequence-in-build.md — 빌드 안 자동 sequence 영구 금지.claude/rules/automation-multi-key-sequence-pattern.md deprecated 명시 (historical 보존)







coord-world-btn/coord-local-btn
text-element filter 제거. __selectable 만 유지 (TextField 안 text element).
__selectable) 사이에 끼움.__selectable / text-element filter 추가.
?(VisualElement)[unity-base-field__input.unity-base-slider__input] — ListView 안 scroll slider input.

unity-* prefix filter 추가:`csharp`





_lnbActiveIdx >= 0 → HideLnbDropdown() + _lnbTabs[restoreIdx]?.Focus() 메뉴바 헤더 복귀





:focus pseudo-class 동작 보장 안 됨. USS :focus rule 적용 안 됨..c-lnb__menu.is-focused { border 3px gold + background gold-soft } 명시

.c-lnb__menu:focus 직접 추가 (~11줄)border-width:0 override 안 되는 USS load 순서 회피ribbon.uss:34 .c-lnb__menu { border-width: 0 } base rule이 :focus 보다 우선 (USS load 순서).




_lnbTabs[i].focusable = true (L1678) — Tab 순회 + Enter 자동 활성화cmdBtn.focusable = true (L1700) — Tab 순회 + Enter 자동

overActiveDropdown 검증 추가 (8줄)


Factory00.UI.Vector3FieldElement (Task #159 P1 v0.1.426 SSOT) 직접 사용--axis-{x,y,z}-color SSOT 통합Assets/Scripts/Game/Factory00Bootstrap.cs L6335~6360 — SensorVec3Field 단순화


.axis-field / __input / .vector3-field 자체 root cause..axis-field / .axis-field__input / .vector3-field 3 rule 일괄 제거.axis-field 영역 root cause 확정 → v0.1.439+ 1개씩 다시 추가
:focus rule 2 그룹 제거 (v0.1.432에서 추가했던 영역).axis-field / __input / .vector3-field 유지 (.axis-field__label은 v0.1.436에서 이미 제거):focus + .axis-field 조합이 root cause → :focus rule만 단독으로 v0.1.432 시점 회복.axis-field 자체 또는 __input / .vector3-field 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 유지.axis-field__label 안 어떤 property가 root cause.axis-field base / __input / .vector3-field 영역
.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 유지.axis-field--x 영역 root cause → -- modifier 회피 패턴.axis-field rule 또는 __label 자체 root cause → 추가 binary
.axis-field--{x,y,z} .axis-field__label 안 var(--axis-x-color) → 직접 rgba(220, 80, 80, 0.85) 등--axis-{x,y,z}-color 토큰은 유지 (사용 X 상태)var() 사용이 root cause = var() 회피 패턴 적용.axis-field rule 자체 또는 -- BEM modifier가 root cause

: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)rgb(255, 217, 115)). 토큰/var() 영역 분리 검증.:focus rule 안전 (root cause 아님) → v0.1.433 .axis-field 추가:focus rule = root cause 확정 → revert + 다른 안전 패턴:focus rule 2 그룹 단독 추가

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) 제거--axis-{x,y,z}-color 토큰 제거
Action applyInputStyle = (target) => { ... }; local closurestatic void ApplyInputStyle(TextField target) 메서드 추출axisIdx == 0 ? working.x : axisIdx == 1 ? working.y : working.z 3항 연산자 체인working[axisIdx] Vector3 indexerApplyInputStyle static method 추출#if false 영구 제거 (룰 binary-search-code-tracking.md)
Axis enum 중복 → 단일 Factory00.UI.AxisKind SSOT.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.EditableVec3Row — Factory00.UI.AxisFieldScrubElement.Axis.X → Factory00.UI.AxisKind.XAxisKind.cs 1곳만 갱신:.axis-field--{w,roll,pitch} 추가만 의무Axis → AxisKind 치환Axis → AxisKind 치환 + Axis propertyAxisFieldScrubElement.Axis → AxisKind#if false 영역 영구 제거 + Inspector 외 단순 좌표 입력 위치 AxisFieldElement 치환
PointerMoveEvent drag-scrub: _value = newValue + _tf.SetValueWithoutNotify → this.value = newValue_inspectorDragLockSince = locked ? Time.time : 0f (안전망)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 토큰.axis-field-scrub__strip USS class 3 라인 추가
Assets/Scripts/UI/AxisFieldScrubElement.cs 신규 ~270라인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 유지#if false 옛 코드 영구 제거 + Bootstrap 다른 단순 좌표 입력 위치 (Sensor / Modbus) AxisFieldElement 치환 (P2)
--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 컬러 라벨 적용--axis-{x,y,z}-color 3 토큰 신규.axis-field 절 신규 (~35라인)
`csharp`
/ 검색 focus (TextField 안 / 입력 가능):focus pseudo-class — *:focus 전역 회피 (잡음 방지):unity-text-field:focus > input — 골드 1px borderunity-button:focus — 골드 1px borderunity-toggle:focus — 골드 1px borderunity-list-view:focus — 골드 1px borderunity-slider:focus — 골드 1px border--gold-edge-strong (rgb 255,217,115, alpha 0.75) 활용.
CameraViewController.UpdateOrbit/UpdateFirstPerson/UpdateOrtho — cursorInside 가드 추가cursorInside && 가드Input.mousePosition Screen.width/height 범위 검증Bootstrap.Update ESC handler cascade if + handled → else if 정리focus-key-isolation.md 보강 — Win32 표준 입력 패턴 표 + Charles Petzold/Raymond Chen 참조
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 명시 해제" 두 절 신규
focusedElement.Blur() 호출 추가
IsAnyUIFocused() 신규 헬퍼 — 모든 focusable element 포커스 검증 (TextField 외 Button/ListView 포함).claude/rules/focus-key-isolation.md 신설 (워크스페이스 전역)


leftPanel.width + ribbon.height 보정 후 viewport 중앙 좌표 갱신

IsChildOf O(N²) — 8000개 부품 root click 시 64M operationnew Vector2(x, Screen.height - y) 명시 Y 반전_gizmo.DraggingAxis >= 0 시 매 frame HighlightSelectedParts 호출
if (!overUI && _lnbActiveIdx >= 0) HideLnbDropdown() 주석 처리 (QA-104 회기 fix). QA-097은 잔존.inViewport && _lnbActiveIdx >= 0 조건으로 변경if (!overUI...) | PASS | FAIL (회기) |if (inViewport...) | PASS | PASS |


sharedMaterial = mat | material = mat (Unity 자동 instance) |sharedMaterial.color = ... | material.color = ... (instance 변경) |sharedMaterial.color = ... | material.color = ... |
_orbitPanOffset = Vector3.zero 명시 reset 추가
_childrenByParentId 캐시 미갱신 → 계층 hierarchy 무시 → 모두 root 표시RebuildVisibleParts 미호출 → ListView itemsSource stale_partList.Rebuild() 미호출 → UI 갱신 안 됨 → 부품 click 시 lazy 갱신BuildPartDepthCache + BuildPartByTransformCache + RebuildVisibleParts + _partList.Rebuild() 명시 호출Assets/Scripts/Game/Factory00Bootstrap.cs OpenTwnPath ApplyTwnPayload 직후 — 캐시 재빌드 + ListView Rebuild 4건 호출
&& !Input.GetKey(KeyCode.LeftAlt) && !Input.GetKey(KeyCode.RightAlt)
if (_mode == CameraViewMode.FirstPerson) return; — 1인칭 상태 갇히면 모든 뷰 메뉴 무동작
.c-sidebar-edge-btn--collapse right -40px

_subWindowOverlay.BringToFront() 호출 추가 (L8170)root.Add(_subWindowOverlay)는 마지막 자식이지만 LNB hud-root.BringToFront (L3456) + ribbon-commands reparent (L1605) 후속 호출 시 z-order 뒤로 밀림Assets/Scripts/Game/Factory00Bootstrap.cs L8170 — BringToFrontwiki/index.html / wiki/latest-builds.html — 제거
Assets/Scripts/Game/Factory00Bootstrap.cs L5028 — OnDragEnded HighlightSelectedParts 호출
Assets/Scripts/Game/Factory00Bootstrap.cs L4373~4395 — Alt+mnemonic 7키 매핑
string stepSourcePath 필드 신규 — STEP 원본 경로 직렬화_lastStepPath 변수 추가 (런타임 capture)OpenTwnPath async 변경Assets/Scripts/Project/TwnProjectFile.cs L77~80 — stepSourcePath 필드Assets/Scripts/Game/Factory00Bootstrap.cs L2619~2623 — _lastStepPath 변수Assets/Scripts/Game/Factory00Bootstrap.cs L1773 — STEP 임포트 captureAssets/Scripts/Game/Factory00Bootstrap.cs L3023 — SaveProject 저장Assets/Scripts/Game/Factory00Bootstrap.cs L2752~2800 — OpenTwnPath async + 자동 재임포트
t.position = _initialPositions[idx] + delta — world position, 정상 |Assets/Scripts/Game/Factory00Bootstrap.cs L4968~5005 — UpdateGizmoTargets hierarchy dedup 추가
PhotoSensorVisualizer.cs L147 — Color hi = new Color(1f, 1f, 1f, 0.95f) → Color(1f, 0.15f, 0.15f, 0.95f) (흰색 → 빨강)WireframeService.cs 신설 (SSOT) — RenderPipelineManager.beginCameraRendering hook + GL.wireframe + PlayerPrefs 저장CameraViewController.cs L192~200 — F3 KeyDown → ToggleWireframe + OnWireframeToggled callbackRibbon.uxml L69 — view-wireframe button 추가Factory00Bootstrap.cs L2408~2424 — view-wireframe binding + FlashToastAssets/Scripts/Game/WireframeService.cs 신설 (~75라인, SSOT)Assets/Scripts/Game/CameraViewController.cs L192~200 — F3 KeyDown + L178 OnWireframeToggled callbackAssets/UI/Components/Ribbon.uxml L69 — view-wireframe buttonAssets/Scripts/Game/Factory00Bootstrap.cs L2408~2424 — button binding + 토스트Assets/Scripts/Sensors/PhotoSensorVisualizer.cs L147 — red color
CameraViewMode.Default 분기 → ApplyPresetCameraPosition() 호출로 변경. v0.1.391 fix의 fallback 순서 잘못 (target.position 우선) → 모든 orbit 모드 (Default/Top/Side/Front/Right/Isometric) 동일 SSOT 사용 (_boundsCenter 우선 → target.position fallback)target.position 우선 → STEP 모델 LoadedRoot.position = 원점, BBox center 다른 위치 |_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
Assets/Scripts/Game/CameraViewController.cs L530~535 — UpdateFirstPerson Space/C 추가Assets/Scripts/Game/CameraViewController.cs L330~348 — ApplyMode FirstPerson target null fallback
PhotoSensorVisualizer.Update L72~83 — ownerPart cachedTransform inactive 시 visualizer hide. DeleteCommand SetActive(false) 호출 시 visualizer GameObject는 SensorPollingDriver 자식이라 parent inactive 상속 안 됨 → 명시 검증.OnSelectionChanged L4715~4717 — SensorPollingDriver / ActuatorDriver SetSelectedPart(root) 호출 추가 (root null 포함). ESC/빈 click 시 visualizer 가시성 즉시 해제.Assets/Scripts/Sensors/PhotoSensorVisualizer.cs L72~83 — Update ownerPart activeSelf 검증Assets/Scripts/Game/Factory00Bootstrap.cs L4715~4717 — OnSelectionChanged SetSelectedPart 호출
FocusInEvent + MouseDownEventIsInspectorEditFocused + IsInspectorRecentlyInteracted 가드 |Assets/Scripts/Game/Factory00Bootstrap.cs L5186~5198 — FocusInEvent + MouseDownEvent 추가 (2건)
c-sidebar-edge-btn--collapse right -27px → -50px. splitter 6px + border 2px + body border + 24px gap 충분 회피_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 -50pxAssets/Scripts/Sensors/PhotoSensorVisualizer.cs L133~165 — _targetLR width 카메라 거리 비례 갱신
[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.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건 → 주석 치환
#if false ... #endif 제거 — PneumaticStrokeBar visualizer 자동 부착 활성화#if false Pneumatic 자동 visualizer 부착 영구 비활성화 (v0.1.382 잔존) |#if false 제거 후 정상 활성화.Assets/Scripts/Actuators/ActuatorDriver.cs L44~57 — #if false 제거 + 활성화 코멘트
CameraViewMode.Default 분기 fallback 추가 — target null 시 _boundsCenter fallback, 빈 씬 시 월드 원점case 분기)if (_mode == FirstPerson) return; _orbitYawPitch 갱신; ApplyMode(Default); |if (target != null) {...} 가드 = target null 시 cam.transform 갱신 안 됨 |`csharp`Assets/Scripts/Game/CameraViewController.cs L272-285 — ApplyMode Default 분기 fallback 추가
Assets/Scripts/Game/CameraViewController.cs — enum +2, ApplyMode +14라인, Update 매핑 변경Assets/Scripts/Game/Factory00Bootstrap.cs — HandlePartFilterShortcuts F4~F8 5건 제거
Assets/Scripts/Game/Factory00Bootstrap.cs — 17라인 삭제 + 3라인 갱신 (총 -14라인, 9608→9594)
Assets/Scripts/Game/Factory00Bootstrap.cs — 5라인 추가 + 4라인 추가 (DuplicateCommand.Execute)









[step-import] wiring: OK parent=cmds-tools → wiring 정상[step-import] click 발화 로그 부재 → click event 차단 확정Factory00Bootstrap.cs:1654 root.RegisterCallback(TrickleDown) 핸들러activeDropdown.worldBound.Contains(evt.position) 단독 검증 → cmds-tools worldBound 결함 시 falseHideLnbDropdown() 호출 → dropdown display:None 전환 → button click event 발화 차단activeDropdown.Contains(tgt as VisualElement)Assets/Scripts/Game/Factory00Bootstrap.cs:1654 (8 라인 — 7 추가 + 1 코멘트)[step-import] click 발화 로그 출력 확인

if (cmdImportStep == null) { LogError } else { Debug.Log + pickingMode = Position + 토스트 + try/catch } ← 회기 도입var cmdImportStep = root.Q_lastInspectorInteractionTime + 1.5s + RegisterCallback trickle-down)Factory00Bootstrap.cs cmd-import-step 인라인 람다 복원 (~50 라인)Factory00Bootstrap.cs RunStepImportAsync 메서드 삭제 (~80 라인)Factory00Bootstrap.cs Ctrl+I 단축키 영역 삭제 (~10 라인).claude/rules/user-says-it-worked-trust-first.md 신규 — 사용자 "잘되던 기능" 즉시 신뢰 의무feedback_user_says_it_worked_before.md 메모리와 페어
expandAllAction RefreshItems → Rebuild 교체 (collapseAll과 일관)_partList.schedule.Execute(() => Rebuild()).ExecuteLater(0) — 1프레임 delayed 추가 Rebuild로 viewport 완성 후 재갱신[step-import] 로그 사용자 PC 직접 검색 필요Factory00Bootstrap.cs ~8라인 (expandAll Rebuild + 2곳 delayed Rebuild)
ComputePartBounds 안 GetComponentsInChildren(true) 이 Visualizer mesh 포함 → bounds center 이동 → Gizmo 위치 오프셋Factory00.Core.PartBoundsExclude (Assets/Scripts/Core/PartBoundsExclude.cs, 5라인) + ComputePartBounds 안 GetComponentInParent() != null skip 가드ActuatorDriver.cs L48 (PneumaticStrokeBar visualizer)Sensors/PhotoSensorVisualizer.cs L55 (LineRenderer cone)Actuators/PneumaticStrokeBarVisualizer.cs L79 (LineRenderer bar)RefreshItems() 만 호출 → ListView row의 bindItem이 cached _foldExpanded state 사용 → fold triangle (▸/▾) visual 갱신 안 됨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라인)
AddServoAxisToPart — RebuildVisibleParts + _partList.Rebuild()AddPneumaticToPart — 동일AddTowerLampToPart — 동일AddRotaryPneumaticToPart — 동일AddRotaryActuatorToPart — 동일AddPhotoSensorToPart — 동일Factory00Bootstrap.cs 6 위치 (~24라인 추가)
_lastInspectorInteractionTime + 1.5s grace — DropdownField popup focusController 미포착 회귀 안전망!IsInspectorEditFocused && !IsInspectorRecentlyInteracted 둘 다 충족 시 RenderInspectorFactory00Bootstrap.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 + 진단)
cmdImportStep.pickingMode = PickingMode.Position 강제cmds-tools dropdown 안 click 발화 안 되어도 직접 import 호출Factory00Bootstrap.cs L1717~1740 (cmd-import-step 안전망) + L4150~4170 (Ctrl+Shift+I 단축키) ~25라인[step-import] 검색 → wiring 또는 reflection 실패
if (cmdImportStep != null) 가드만 있었음)silent-button-toast.md 위반 — listener wiring 실패 또는 PickStepFile 호출 자체 실패 시 사용자에게 아무 피드백 없음Debug.LogError 출력으로 wiring 실패 진단 가능Factory00Bootstrap.cs L1717~1736 (~15라인 추가)%APPDATA%/../LocalLow/factory00/factory00/Player.log) 안 [step-import] 로그 검색wiki/topics/release-notes/v0.1.367.md 신규
[^&]*? 가 0 길이 매칭 → 본문 손실



wiki/handoff-pm-action.html — pm-fetched-at div 신규Tools/qa/publish-build-auto.sh — sed 패턴 추가

ProjectIO.cs — Save/Load Transform 직렬화Factory00Bootstrap.cs — File→New ClearImportedScene
Factory00Bootstrap.cs — DuplicateRotaryPneumaticActuators + ResetActuatorPlcBinding
Factory00Bootstrap.cs — collapseAllAction 5라인 hotfix
Factory00Bootstrap.cs — PartFilterMode + ApplyPartFilterMainHUD.uxml — [▼필터] 드롭다운 추가
Factory00Bootstrap.cs — PartFilterMode + ApplyPartFilterMainHUD.uxml — [▼필터] 드롭다운 추가





















PneumaticActuator.cs — state machine 단순화PneumaticPlcBridge.cs — CoilEStop → CoilStopFactory00Bootstrap.cs — UI 라벨 갱신.twn 자동 마이그레이션 로직

Assets/Scripts/Importers/StepImportService.cs 신규 (~130라인)Factory00Bootstrap.cs — cmd-import-step 핸들러 wiringTools/converter-py-slim/ — Python 3.11.9 embedded + cadquery-ocp
Assets/Scripts/Importers/StepImportService.cs 신규 (~130라인)Factory00Bootstrap.cs — cmd-import-step 핸들러 wiringTools/converter-py-slim/ — Python 3.11.9 embedded + cadquery-ocp
Assets/Scripts/Importers/StepImportService.cs 신규 (~130라인)Factory00Bootstrap.cs — cmd-import-step 핸들러 wiringTools/converter-py-slim/ — Python 3.11.9 embedded + cadquery-ocp
Assets/Scripts/Importers/StepImportService.cs 신규 (~130라인)Factory00Bootstrap.cs — cmd-import-step 핸들러 wiringTools/converter-py-slim/ — Python 3.11.9 embedded + cadquery-ocp
Assets/Scripts/Importers/StepImportService.cs 신규 (~130라인)Factory00Bootstrap.cs — cmd-import-step 핸들러 wiringTools/converter-py-slim/ — Python 3.11.9 embedded + cadquery-ocp

Assets/Scripts/Importers/StepImportService.cs 신규 (~130라인)Factory00Bootstrap.cs — cmd-import-step 핸들러 wiringTools/converter-py-slim/ — Python 3.11.9 embedded + cadquery-ocp

























MitsubishiPlcDriverComponent.UseMock=true. SDK 부재 빌드/실행 가능. SDK 도착 후 UseMock=false 1줄 전환.comm-mitsubishi-mx-inspector)wiki/latest-version.js 신규 — 3 페이지 단일 SSOT/bump-version 스킬 latest-version.js 통합latest-version-ssot.md 신규
Factory00Bootstrap.cs:5763 disBtn | SetEnabled(false) 제거 + opacity = 0.55f (시각 비활성) + 토스트 메시지 명확화 | +2 -1 |
wiki/topics/edit-cut-snapshot-options.md) 기반 옵션 B 채택. DeleteCommand 가 SetActive(false) 패턴이라 cachedTransform 살아있음 -> DuplicateCommand 안 Instantiate 정상 동작. 추가 SetActive(true) 1줄로 Cut 후 Paste 시 새 GameObject active 보장.KeyCode.X -> CutSelected() | +1 |CutSelected 메서드 | Copy + DeleteSelectedPart 직렬 호출 + 토스트 | +18 |edit-cut 활성화 | silent-button listener -> CutSelected() 호출 | -2 +3 |SetActive(true) | Cut 후 Paste 시 inactive 상속 회피 | +2 |``UnityEngine.Object.Instantiate 재귀)
chCount<=0 시 return -> 다중 부착 시나리오에서 다른 lamp skip | continue 로 변경 + 주석 | 1 |CopySelected() SSOT 우회 | 우클릭 대상 선택 집합에 없으면 _selectedParts 임시 갱신 후 CopySelected() 호출 | +6 |Mathf.Clamp(v, 0.1f, 5.0f) 추가 | 1 |GetComponentsInChildren allocation 비용 — Material null 시점만 trigger. 현 디자인 의도 일치 (다수 lamp 시 풀링 P3 사이클)lamp.LampCount vs Channels.Count 동기 — InitializeChannels 가 항상 동기 처리. 부분 삭제 경로 없음factory00-windows-x64-v0.1.288-stable.zip 후보.
×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 |Mathf.Max(0.1f, ...) 가드 — 0 또는 음수 입력 시 최소 0.1 (보이지 않는 부품 방지).[System.Serializable] 자동 처리 -> Save/Load 자동 통과. 기존 .twn 파일은 HdrIntensity 필드 누락 시 default 2.5 적용 (JsonUtility 기본 동작).tower-lamp-ch0 등 이름 매칭 (현재 인덱스 기반)
BuildObjectMenuItems | Copy / Paste 항목 2개 추가 (지우기 위에) | +20 |``
10abd81 신규 승격). v0.1.268 에서 P2 미구현으로 비활성 처리됐던 Edit 탭 Cut/Copy/Paste 버튼 중 Copy / Paste 활성. Cut 은 P2 후속 사이클 분할 (사이클 크기 안전).List _clipboard | +3 |_clipboard.Clear() 추가 (.twn 새 로드 시 reset) | +2 |``cachedTransform == null 검출 -> skip + 토스트 안내Bus property / _selectedParts / DuplicateCommand IEditCommand / 단축키 패턴 모두 사전 검증 PASS_clipboard 클래스 필드 (메서드 로컬 X)
TowerLampEmissionDriver.cs | Material[] -> Material[][] (per-channel) 캐시 / ApplyEmission 채널별 색 분배 / OnDestroy + InvalidateLamp 다차원 순회 |``tower-lamp-ch0 등 이름 매칭)
TowerLampEmissionDriver.cs:114-133 | cache valid check (m == null) + stale 시 Destroy + 재생성 |r.materials 반복 호출 + OnDestroy 누락 -> Material instance 누수 | 동상 L125-129 | 한 번만 fetch + OnDestroy 안 _matCache 전 Destroy |_blinkOn stale | Factory00Bootstrap.cs:5833 LampCount 슬라이더 | InvalidateLamp(DriverInstanceId) 호출 추가 (cache + blink phase 정리) |ch.IsOn vs Sim 토글 SSOT 충돌 | Factory00Bootstrap.cs:5912-5928 | Sim 토글 SetEnabled(ModbusCoilBase <= 0) + tooltip 명시 |_EMISSION 키워드 불충분 -> 렌더 반영 안 됨 | TowerLampEmissionDriver.cs:128 | globalIlluminationFlags = RealtimeEmissive 추가 |TowerLampEmissionDriver.cs Update() | 100ms throttle (k_UpdateInterval = 0.1f) — blink 정확도 OK |Factory00Bootstrap.cs:5852 | "채널 (LampCount색등)" |TowerLampEmissionDriver.InvalidateLamp(string driverInstanceId) — lamp 제거 / 재구성 시 Material instance Destroy + cache + blink phase 정리. RemoveTowerLampFromPart + LampCount 슬라이더 양쪽에서 호출.<= 0 vs == 0 의도 명시 | v0.1.284 코멘트 |
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 |``[System.Serializable] 자동 처리 -> Save/Load 자동 통과 (별도 코드 0)
_EmissionColor HDR 효과는 v0.1.282 분리.`csharp`COIL:{base+i} 주소로 매핑. v0.1.282 Bridge가 이 값을 폴링.``Sim 토글 변경 시:ch.IsOn = !ch.IsOnEventBus.Publish(TowerLampStateChangedEvent) 발행 — v0.1.282 Emission Driver 가 구독Coil Base 정수 입력. 0~9999 clamp. 0 = 미연결.ch.IsOn에 따라 색박스가 진하게(1.0) / 어둡게(0.30) 표시. PLC 신호 또는 Sim 토글 변경 즉시 반영.TowerLampStateChangedEvent 발행 (v0.1.282 구독자 추가) |Assets/Scripts/Outputs/TowerLampComponent.cs — ModbusCoilBase 필드 추가Assets/Scripts/Game/Factory00Bootstrap.cs — RenderTowerLampCard Sim 토글 + Coil Base 필드 + IsOn opacity (~30라인 추가)ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.280 -> 0.1.281COIL:100~103 매핑 준비_EmissionColor HDR + Blink Update) + .twn 직렬화 통합
TowerLamps 가 있으면 Inspector 하단에 새 섹션 출현. 첫 부착 시 "+ 타워램프" 버튼만 노출.TL-{8자리} [N색등] + 삭제 버튼InitializeChannels(N) 호출로 채널 리스트 재생성. Inspector 즉시 재렌더#N 위치 라벨 (24px)ColorFromPresetName(string) / NearestColorPresetIndex(Color) — RGB 거리 최소값으로 dropdown 초기값 매칭. spec QA-018 답변 (B안 URP _EmissionColor HDR) 대비 채널 색상 SSOT.AddTowerLampToPart(Part) — 부품당 1개 강제, 토스트 안내RemoveTowerLampFromPart(Part, TowerLampComponent) — 토스트 + Inspector 재렌더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
Assets/Scripts/Outputs/TowerLampComponent.cs (신규)`csharp`Assets/Scripts/Events/TowerLampEvents.cs (신규) — TowerLampStateChangedEvent readonly structAssets/Scripts/Events/EventBus.cs — OnTowerLampStateChanged event + Publish(TowerLampStateChangedEvent) overloadAssets/Scripts/Core/Part.cs에 List TowerLamps 필드 추가. 다른 컴포넌트 리스트(Sensors / Actuators / VacuumEjectors 등)와 동일 패턴.`xml`Assets/Scripts/Outputs/TowerLampComponent.cs (신규) — TowerLampChannel + TowerLampComponentAssets/Scripts/Events/TowerLampEvents.cs (신규) — TowerLampStateChangedEventAssets/Scripts/Events/EventBus.cs — Publish overload + eventAssets/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_EMISSION keyword + _EmissionColor HDR) + Signal Sim 수동 제어
factory00.sidebar_pinned에 영구 저장됩니다. 앱 재실행 시 직전 모드 그대로 복원됩니다._leftPanelVM.ToggleCollapse() 호출로 패널이 다시 펼쳐집니다. 클릭하지 않아도 마우스 진입만으로 자동 슬라이드 인 효과.`csharp`Bus.Publish(new SidebarPinChangedEvent(...)) 호출. 향후 다른 UI 영역에서 압정 상태 변경을 구독할 수 있습니다.element.schedule.Execute(...).StartingIn(1000) 패턴으로 1000ms 지연 타이머를 구현했습니다. MouseEnterEvent 발생 시 hideTimer?.Pause()로 즉시 취소 — 마우스가 재진입하면 hide가 일어나지 않습니다.Assets/UI/MainHUD.uxml — sidebar-pin-btn 추가 (접기 버튼 좌측, 압정 토글)Assets/Scripts/Events/SidebarEvents.cs (신규) — SidebarPinChangedEvent readonly structAssets/Scripts/Events/EventBus.cs — OnSidebarPinChanged event + Publish overloadAssets/Scripts/Game/Factory00Bootstrap.cs — 압정 wiring + MouseLeave/Enter 타이머 + 미니 리본 hover slide-in (~50라인)ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.277 -> 0.1.278
<- 접기 버튼이 추가됩니다. 기존 Ribbon 좌측 햄버거 ≡ 버튼은 그대로 유지되며 동일한 _leftPanelVM.ToggleCollapse() 호출입니다.`xml`▶이 표시됩니다.`xml`display:nonedisplay:flex (자동 표시)_leftPanelVM.ToggleCollapse() -> 패널 복원_leftPanelVM.ToggleCollapse()를 호출합니다. 사용자가 어느 경로로도 토글 가능합니다._leftPanelVM.OnCollapsedChanged 콜백에 미니 리본 visibility 라인을 추가했습니다.`csharp`Assets/UI/MainHUD.uxml — sidebar-collapse-btn (parts-section 헤더 우측) + sidebar-mini-rail (씬 좌측 floating) 추가Assets/Scripts/Game/Factory00Bootstrap.cs — sidebar-collapse-btn / sidebar-mini-rail wiring + collapsed 콜백에 미니 리본 visibility 동기화 (~15라인)ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.276 -> 0.1.277<- 버튼이 보이는지 확인<- 클릭 -> 좌측 패널 접힘 + 씬 좌측 가장자리에 노란 ▶ 미니 리본 표시▶ 클릭 -> 좌측 패널 복원≡ 햄버거 + F11 단축키 모두 같은 토글 동작 (회귀 없음)SidebarPinChangedEvent + PlayerPrefs factory00.sidebar_pinned)
studio-panel-resize-pin-summary.md r001)의 P1 범위는 "패널 상하 리사이즈 + 리사이즈 바 hover 인디케이터 + PanelResizedEvent 발행"입니다. 다행히 기존 codebase에 상하 리사이즈 드래그 로직 + 커서 변경은 v0.1.101~167 사이클에서 이미 구현되어 있었습니다. 이번 P1 사이클은 spec이 요구한 hover accent 색상 + 드래그 중 더 진한 색상 + 이벤트 발행 부분만 추가하는 형태입니다.EventBase UnityEvent 패턴 | readonly struct *Event + Bus.Publish SSOT | adapter — PanelResizedEvent readonly struct 신규 |PanelResizedEvent { PanelId, NewHeightPx } | 동일 구조 가능 | PASS — Assets/Scripts/Events/PanelEvents.cs 신규 |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 색상 + 이벤트만 추가 |SetBuiltinCursor(handle, 2) 적용 (v0.1.167) | PASS — 별도 변경 X |`csharp`parts-section / inspector-section 두 패널 리사이즈 종료 시 Bus.Publish(new PanelResizedEvent(...)) 호출.rgba(255,255,255,0.08) (회색)rgba(255,217,115,0.30) (accent 옅게)rgba(255,217,115,0.55) (accent 진하게)MouseEnterEvent / MouseLeaveEvent / PointerDownEvent 콜백으로 색상 변경합니다.parts-inspector-resize (부품 ↔ 프로퍼티 경계)inspector-motor-resize (프로퍼티 ↔ 모터 경계)left-panel-resize)는 이번 spec 범위 외 (P2~P3 작업).Assets/Scripts/Events/PanelEvents.cs (신규) — PanelResizedEvent readonly structAssets/Scripts/Game/Factory00Bootstrap.cs — partsResize + inspMotorResize 두 곳에 hover/드래그 색상 + Bus.Publish 추가 (~50라인)ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.274 -> 0.1.276 (v0.1.275는 docs-only로 build skip)factory00.parts_section_height / factory00.inspector_section_height 갱신 + 앱 재실행 시 복원SidebarPinChangedEvent + PlayerPrefs sidebar_pinned
OpenCollisionResultsSubWindow)에 backdrop click -> 닫기 동작이 누락되어 있었습니다. 같은 모달 패턴을 사용하는 OpenPartInSubWindow (v0.1.030 "새창에서 보기")에는 이미 동일 동작이 있어 사용자 입장에서는 일관성이 깨진 상태였습니다.`csharp`dialog) 영역의 클릭은 evt.target != _subWindowOverlay이므로 닫히지 않고, 배경(_subWindowOverlay) 직접 클릭만 모달을 닫습니다. 항목 클릭 동작과 충돌 없이 동작합니다.Assets/Scripts/Game/Factory00Bootstrap.cs — OpenCollisionResultsSubWindow 끝에 backdrop click 콜백 5라인 추가ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.273 -> 0.1.274
Camera.main?.GetComponent() 즉석 조회가 두 곳에서 중복되어 있어 헬퍼 추출이 권장된다"고 중간 결함으로 지적했습니다. 이번 사이클에서 헬퍼 메서드를 추가하고 두 호출처를 모두 교체했습니다.`csharp`Bootstrap.cs:3045 (더블클릭 카메라 포커스) — GetCameraViewController() 호출로 교체Bootstrap.cs:6719 (Collision Check 결과 윈도우 행 클릭) — 동일HEADER_TITLE_AUTOGEN / FACTORY00_GIT_AUTOGEN / COLLAB_GIT_AUTOGEN 3개 marker는 hook 코드가 빠져 있어 수동 갱신에 의존하고 있었습니다. 이번 사이클에서 자동화 완성.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`handoff-pm-action.html의 PM 액션 패널 본문(spot-check 다이어트 등)만 남게 됩니다.camCtrl not in scope 컴파일 에러로 빌드 abort가 발생한 회고를 룰에 반영했습니다.`bash`var camCtrl = ... (로컬) 만 있고 필드 선언이 없으면 신규 메서드는 즉석 조회 패턴 또는 헬퍼 메서드를 사용해야 합니다.Assets/Scripts/Game/Factory00Bootstrap.cs — GetCameraViewController() 헬퍼 신규 + 2곳 교체 (~15라인)Tools/qa/publish-build-auto.sh — HEADER_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.273handoff.html의 8개 marker 모두 자동 갱신 확인. h1 제목·factory00 commit hash·협업자 pull 정보가 모두 최신 값으로 표시
Bounds.Intersects()는 두 박스가 정확히 한 면만 접촉해도 hit으로 처리합니다(inclusive). 협업자 spec은 면 접촉만으로는 겹침이 아니라고 명시했으므로 각 axis에 대해 epsilon(0.1mm)만큼 실제 겹침이 있어야 hit으로 판정하는 헬퍼를 만들었습니다.`csharp`_subWindowOverlay 모달 패턴(v0.1.030 "새창에서 보기")을 재사용하여 일관된 UI를 제공합니다.camCtrl.FocusOnBounds() 호출 -> 카메라 자동 포커스Assets/Scripts/Game/Factory00Bootstrap.cs — RunCollisionCheck() + StrictBoundsOverlap() + OpenCollisionResultsSubWindow() 신규 약 150라인. 기존 review-collision 핸들러 1줄로 단순화Assets/UI/Components/Ribbon.uxml — review-collision tooltip 갱신 (3 모드 + 카메라 포커스 안내)ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.271 -> 0.1.272
Factory00Bootstrap.cs:3531 polling + SettingsPanelViewModel.cs:92 RegisterCallback)에 분산되어 SSOT 헬퍼 추출이 필요할 수 있다"는 critic 지적이었습니다.Factory00Bootstrap.cs:3531 (Input.GetKeyDown polling) — UnityEngine.Input 표준 경로SettingsPanelViewModel.cs:92 (RegisterCallbackSettingsVM.Toggle()을 호출합니다. SSOT는 Toggle()이며, 그 안에 150ms _lastToggleTime 시간 throttle(SettingsPanelViewModel.cs:247)이 동시 발화 시 두 번째 호출을 안전하게 차단합니다.qa-test-by-repro.md §1.2에 따라 PostMessage WM_KEYDOWN 자동화에서 첫 번째 dispatch는 RegisterCallback path로 잘 도달하지만, polling 경로는 Unity Input pipeline의 별도 호출 시점을 캐치할 수 있어 두 경로 모두 유지하는 것이 회귀 안전성을 보장합니다.Factory00Bootstrap.cs:3531 및 SettingsPanelViewModel.cs:92에 의도 주석을 강화했습니다. 두 binding이 의도된 이중 안전망이며, SSOT는 Toggle() 단일 메서드 + 150ms throttle임을 명시했습니다.Bootstrap.cs:3534 [shortcut] F10 -> SettingsVM.Toggle).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
[[설정]옵션] 버튼을 추가하여 ON/OFF 토글 가능하게 해달라"고 요청하셨습니다.autoTrackingScroll 플래그로 구현되어 있었습니다. 다만 ON/OFF를 토글할 사용자 노출 UI가 없어 사실상 켜진 상태로만 사용되고 있었습니다. 이번 사이클에서는 spec이 요청한 노출 UI를 추가하는 작업이 핵심입니다.[설정] 버튼을 추가했습니다. 기존 [펼치기] [접기] 우측에 배치되어 협업자 spec([▼필터] [모두펼치기] [모두접기] [[설정]옵션])의 의도에 맞춰져 있습니다.``[설정] 버튼 클릭 시 ContextMenu가 펼쳐지며 다음 항목이 표시됩니다.``autoTrackingScroll 플래그 값을 즉시 반영합니다. 클릭하면 토글되며 상태 변경을 토스트("오토 트래킹 ON" 또는 "OFF")로 안내합니다.PlayerPrefs("factory00.auto_tracking_scroll") SSOT가 v0.1.138부터 존재합니다. spec 그대로 세션 임시로 변경하면 SSOT 분열이 발생하므로, 기존 PlayerPrefs 영구 저장 정책을 유지했습니다. 사용자 선호도가 앱 재시작 후에도 보존되어 오히려 UX 측면에서도 우수합니다. 협업자 spec과의 미세한 차이는 향후 라운드에서 답변드릴 예정입니다.PickPartUnderMouse() -> SelectPartFromExternal(picked) 경로에서 이미 다음 처리가 되어 있습니다.`csharp`Assets/UI/MainHUD.uxml — parts-toolbar에 parts-toolbar-options ([설정]) 버튼 추가Assets/Scripts/Game/Factory00Bootstrap.cs — parts-toolbar-options ContextMenu wiring (autoTrackingScroll 토글 + PlayerPrefs 영구)ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.269 -> 0.1.270[설정] 버튼이 표시되는지 확인[설정] 클릭 -> "[[OK]] 씬 클릭 시 부품 리스트 오토 트래킹" 메뉴 표시[설정] 다시 클릭 -> 체크 해제 -> 씬 클릭 시 스크롤 변화 없음 (선택만 변경)
4278c77)에서 누적 18개 QA 항목을 [완료] 완료 확정해 주셨습니다. 사용자 명시("협업자 git pull 했을 때 답변받거나 더이상 유효한 내용 아니면 handoff에서 삭제하여 문서 다이어트")에 따라 handoff-pm-action.html [2] spot-check 박스를 32건 -> 14건으로 정리했습니다._currentTwnPath의 디렉토리 | 현재 작업 중인 .twn 파일이 있을 때 |PlayerPrefs.LastSaveDirectory | 이전 세션에서 사용자가 선택한 마지막 경로 |Application.dataPath/../Project/ | .exe 옆에 자동 생성되는 Project/ 폴더 |.exe 실행 파일 위치 기준 상대 경로 ./Project/)을 따랐습니다.PlayerPrefs.SetString("LastSaveDirectory", ...) 호출 + PlayerPrefs.Save()로 즉시 디스크에 기록합니다. 다음 앱 실행 시 같은 폴더에서 시작합니다.GetTwnDialogInitDir() + RememberTwnDialogDir(filePath) 두 헬퍼로 추출하여 Open 핸들러와 Save 핸들러에서 동일하게 사용합니다. 향후 신규 다이얼로그 추가 시에도 같은 패턴으로 일관성 유지 가능합니다.QA-033/035/036/037/041/044/046/047/048/049/051/054/056/057/058/064/067/068)을 spot-check 박스에서 제거했습니다. 남은 14건은 seal별로 정리하여 표시합니다.Assets/Scripts/Game/Factory00Bootstrap.cs — GetTwnDialogInitDir() + RememberTwnDialogDir() 헬퍼 추출 + Open/Save 핸들러 통합wiki/handoff-pm-action.html — [2] spot-check 박스 다이어트 (32 -> 14건)ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.268 -> 0.1.269/Project/ 폴더가 자동 생성되고 그 폴더에서 시작D:/MyProjects/) 선택 후 저장 -> 저장 성공D:/MyProjects/ 에서 시작 (마지막 경로 기억)[[설정]옵션] 토글)
studio-edit-tab-summary.md)의 그룹 구분에 맞춰 4개 서브그룹으로 재구성했습니다. Office Ribbon의 표준 UX 패턴(상단에 버튼 가로 배치, 하단에 그룹 라벨 텍스트)을 따랐습니다.ribbon.uss에 #edit-cut, #edit-copy, #edit-paste 셀렉터로 opacity 0.35 + 회색 배경 + hover 효과 무력화Factory00Bootstrap.cs에서 세 버튼 모두 SetEnabled(false) 호출하여 클릭 자체를 차단--size-leftpanel-collapsed: 24px (햄버거 ≡ 클릭 영역 확보 목적). 사용자가 보면 패널 영역이 24px 남아있어 "씬이 확장되지 않은 버그"로 보임.--size-leftpanel-collapsed: 0px. F11 접기 시 패널 영역이 완전히 사라져 씬 뷰포트가 좌측 0px까지 확장됩니다.tab-row의 첫 위젯 toggle-left), 접힘 상태에서도 ≡ 클릭으로 패널을 복원할 수 있습니다. F11 단축키도 그대로 동작합니다. 접힘/펼침 변경 시 토스트도 기존처럼 표시됩니다.Assets/UI/Components/Ribbon.uxml — cmds-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 -> 0pxAssets/Scripts/Game/Factory00Bootstrap.cs — Edit Cut/Copy/Paste SetEnabled(false) wire 추가ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.267 -> 0.1.268
MainHUD.uxml — 설정창 4번째 행으로 slider-fp-speed 슬라이더(범위 0.5~10 m/s, 기본값 2) + label-fp-speed FloatField 추가SettingsPanelViewModel.cs — GetFpSpeed / SetFpSpeed 콜백 추가 + 기존 슬라이더 wiring 패턴(_label* -> _value* rename) 일관 적용Factory00Bootstrap.cs — SettingsVM에 콜백 전달 (CameraViewController.fpSpeed 직접 바인딩)TogglePartTransparency)_Surface = 1 한 줄만 설정 -> URP/Lit이 opaque 큐에서 그대로 렌더링되어 알파값이 무시되는 상태였습니다.`csharp`CYCLE_LOG 표는 최근 5건만 노출하고 나머지는 release-notes 링크로 위임wiki/handoff-pm-action.html, 41라인 -> 보강 후 약 130라인)로 분리handoff.html이 자동 갱신되도록 5개 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 링크 |/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.cs — GetFpSpeed / SetFpSpeed 콜백 + 슬라이더 wiringAssets/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 pullProjectSettings/ProjectSettings.asset — bundleVersion 0.1.266 -> 0.1.267https://os-file-server.tail2b816d.ts.net/wiki/handoff.html)에서 PM 액션 패널이 모바일에서 잘리지 않고 잘 보이는지 확인
Bootstrap.cs:3470 Update polling: KeyCode.Escape -> KeyCode.F10SettingsPanelViewModel.cs:86 RegisterCallback: KeyCode.Escape -> KeyCode.F10Ribbon.uxml:28 tooltip: "설정 (ESC)" -> "설정 (F10)"HighlightSelectedParts -> ApplyMaterialHighlight(parts) 호출. 호출 전 ClearMaterialHighlight() 없음 -> _materialBackups에 이전 backup 누적.TickMaterialHighlightPulse()가 매 frame _materialBackups 전체 순회 -> 선택 해제된 부품 + 복제본 renderer의 emission도 변경 -> 시각적 "highlight 잔존".ApplyMaterialHighlight() 진입 시 ClearMaterialHighlight() 호출:`csharp`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
DuplicateCommand.Execute() L6968:`csharp``csharp`ClearAllRuntimeComponents() 안 _duplicateCount?.Clear() 추가. 새 .twn 로드 시 카운터 초기화.Assets/Scripts/Game/Factory00Bootstrap.cs (+10라인) — _duplicateCount Dictionary + DuplicateCommand 오프셋 누적 + ClearAllRuntimeComponents resetProjectSettings/ProjectSettings.asset — bundleVersion 0.1.264 -> 0.1.265
UpdateGizmoTargets() L4148:`csharp`_targets 전체에 동일 delta 적용 (L816 foreach). 호출 측 누락이 root cause.`csharp`SignalSimulatorPanel.Render() 100ms 폴링 시 _root.Clear() -> ScrollView 재생성 -> scrollOffset=0.`csharp`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
_lastHasSelection=true 주석 "초기 상태와 다르게" 반대 방향 기술 | 주석 명확화 — default=false로 변경 시 회귀 발생 명시 |`csharp``csharp```Assets/Scripts/Communication/Modbus/SignalSimulatorPanel.cs (~20라인) — 미할당 안내 라벨 + 클래스 헤더 주석Assets/Scripts/Game/Factory00Bootstrap.cs (~5라인) — _lastHasSelection 주석ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.262 -> 0.1.263
`csharp``csharp``csharp``csharp``csharp`Assets/Scripts/Communication/Modbus/SignalSimulatorPanel.cs (~45라인) — Pause/Resume 재사용 + PruneDanglingPopup + ComponentId publicAssets/Scripts/Plc/ActuatorPlcBridge.cs (~3라인) — ReadBit catch -> continueProjectSettings/ProjectSettings.asset — bundleVersion 0.1.261 -> 0.1.262
`csharp`Assets/Scripts/Game/Factory00Bootstrap.cs (+15라인) — Button ref 저장 + UpdateEditButtonsEnabled helper + Update 호출ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.260 -> 0.1.261
Enable / MoveForward / MoveBackward / TargetPosition.`csharp``csharp`RenderServoAxisCard Coil 행 4개 -> 5개:``BuildServoControls:`csharp`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
`csharp``csharp`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
RenderServoAxisCard L5739 + RenderRotaryCard L5624 — ActuatorState switch + new Color(...) 4개 매 Inspector 갱신 시 재할당. 0.25s 주기 호출 누적.`csharp`Assets/Scripts/Game/Factory00Bootstrap.cs (~25라인 -> helper 추가 + 2개 switch 제거)ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.257 -> 0.1.258
Factory00Bootstrap.cs:7200 DeleteCommand.Execute() SetActive(false) — 협업자 spec QA-021 ④ "삭제 시 물리·이벤트·폴링 모두 사라짐" 정합. v0.1.172 SetPartVisible 코멘트 "SetActive 금지"는 *visibility toggle* 도메인 한정.`csharp`ToggleVisibilityWithSelection L6858 — 토스트 _selectedParts.Count -> targets.Count로 변경. cachedTransform null 가드 통과한 실제 처리 수 표시.Assets/Scripts/Game/Factory00Bootstrap.cs (~25라인) — DeleteCommand 주석 + Raycast NonAlloc + Comparer + 토스트 fixProjectSettings/ProjectSettings.asset — bundleVersion 0.1.256 -> 0.1.257
PickPartUnderMouse() L4032:`csharp`Physics.Raycast는 가장 가까운 1 hit만 반환. hidden 부품에 hit하면 return null -> 뒤쪽 부품 도달 못 함. fallback 경로(bounds.IntersectRay)도 동일 패턴.`csharp`List<(float dist, Renderer r)> 누적 + Sort + hidden skip.Assets/Scripts/Game/Factory00Bootstrap.cs (~40라인 -> PickPartUnderMouse 일괄 재작성)ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.255 -> 0.1.256
ToggleVisibilityWithSelection(Part triggerPart) L6822:`csharp``csharp``csharp``csharp`Assets/Scripts/Game/Factory00Bootstrap.cs (+5라인) — ToggleVisibilityWithSelection 시그니처 + L2947 호출ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.254 -> 0.1.255
`csharp``csharp`Ribbon.uxml review-show-hidden:충돌: 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/tooltipProjectSettings/ProjectSettings.asset — bundleVersion 0.1.253 -> 0.1.254
RenderActuatorBlock L5478~5496 에 hasServo / hasPneumatic 카드만 렌더. hasRotary 분기 누락. 주석 명시: "Rotary 카드 렌더는 별도 사이클 (있으면 추후 추가)".`csharp`RotaryActuatorActuator 부착 (별도 컴포넌트, PneumaticCylinder Linear/Rotary 드롭다운과 별개)Assets/Scripts/Game/Factory00Bootstrap.cs (+115라인) — RenderRotaryCard 신설 + 분기 추가ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.252 -> 0.1.253
DeleteCommand(Factory00Bootstrap, List) — 단일은 List.Count=1로 wrap. VisibilityCommand 미러 (List`csharp``csharp`Assets/Scripts/Game/Factory00Bootstrap.cs (~90라인 -> DeleteCommand class 일괄 재작성 + DeleteSelectedPart 헬퍼 확장)ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.251 -> 0.1.252
_label* 필드명 (FloatField인데 prefix _label) | _value* rename (_valueMouse/Pan/Fp) |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
Factory00Bootstrap.cs:3203 v0.1.235 진단 Debug.Log 가 매 LMB down 마다 발화 -> v0.1.218 AC "QA 코드 빌드 제거" 직접 위반. Player.log 오염.`csharp``csharp`btn.Blur() (line 1441)이 정상 동작 — 회귀 위험 낮음. 주석 보강 권장 (v0.1.251)._labelMouse/_labelPan/_labelFp 필드명 잔존_label. 다음 사이클 rename 권장.Assets/Scripts/Game/Factory00Bootstrap.cs (~10라인) — QA-006 진단 제거 + 다중 선택 토스트ProjectSettings/ProjectSettings.asset — bundleVersion 0.1.249 -> 0.1.250
`csharp`Assets/Scripts/Game/Factory00Bootstrap.cs (~12라인 -> 확장된 ~20라인) — ribbon -> hud-root 확장ProjectSettings/ProjectSettings.asset (0.1.248 -> 0.1.249)
RunInterfaceEmulationDemo 코루틴 발화 -> Phase A 부품 자동 어셈블리(컴포넌트 자동 추가 + 자동 이동) -> 협업자가 "Scenario Play 자동 시작" 으로 보고.SimulationPlayStartedEvent -> RunInterfaceEmulationDemo 자동 호출 path 0건. F12 키 / sim-interface-emulation 버튼 / present-scenario-play 버튼 (Present Tab) 3개 진입점만 존재 — 모두 명시 사용자 액션.`xml``csharp```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
StopPropagation() 미적용. 실제 root cause는 다름 ↓overUIAtDown 가드 누락`csharp`IsPointerOverUI(UP) = falseoverUIAtDown 가드 있어 차단됨. 단순 click 분기만 가드 누락.`csharp`StopPropagation() 추가 필요 X — Input.GetMouseButton 폴링은 PointerEvent system과 별개로 동작하므로 overUIAtDown 단일 가드로 충분.Assets/Scripts/Game/Factory00Bootstrap.cs (+5라인) — overUIAtDown 가드 추가ProjectSettings/ProjectSettings.asset (bundleVersion 0.1.246 -> 0.1.247)
editDeleteBtn.clicked += () => DeletePart(...) 직접 호출 -> UndoStack 미경유 -> Ctrl+Z 무동작.editDeleteBtn.clicked += DeletePart(...) -> += DeleteSelectedPart()Input.GetKeyDown(KeyCode.Delete) 분기 -> DeleteSelectedPart() — Label은 read-only 위젯. 사용자가 우측 "수치 필드 클릭·입력" 시도하지만 입력 받지 못함. -> . label-pan-sens / label-fp-sens 동일.Label _labelMouse, _labelPan, _labelFp -> FloatField. BindSlider 시그니처 변경.f.SetValueWithoutNotify(round 0.1) (no callback echo)Mathf.Clamp(low~high) + s.SetValueWithoutNotify + setterAssets/Scripts/Game/Factory00Bootstrap.cs (+85라인) — DeleteCommand class + DeleteSelectedPart 헬퍼Assets/Scripts/UI/SettingsPanelViewModel.cs (~15라인) — FloatField 타입 + 양방향 syncAssets/UI/MainHUD.uxml (3 element 타입 변경)Assets/UI/Theme/components.uss (+7라인 .c-settings__numfield)ProjectSettings/ProjectSettings.asset (bundleVersion 0.1.245 -> 0.1.246)
_detailPane.Clear()const float DRAWER_REFRESH_INTERVAL = 0.25f;`csharp``csharp`Assets/Scripts/Game/Factory00Bootstrap.cs (+25라인)IsInspectorEditFocused() 신설 (line 414 부근, IsAnyTextFieldFocused 옆)
toggle-left Button click 후 Unity UI Toolkit 기본 동작 = 버튼 포커스 유지`csharp``csharp`Assets/Scripts/Game/Factory00Bootstrap.cs (+22라인)Assets/Scripts/Game/CameraViewController.cs (+4라인)
`csharp`RemoveRuntimeComponents() 호출하여 모든 MonoBehaviour Destroy`csharp`이름 -> 주소 매핑.ResetSensorPlcBinding / ResetActuatorPlcBinding에 reset 로직 추가.RegisterDuplicatedComponents(Part dup) — DuplicateCommand에서 호출.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 헬퍼 (현재 빈 구현)RegisterDuplicatedComponents(Part dup) 신규 internal 헬퍼
[QA-044 진단] ApplyTwnPayload FAIL: ArgumentException |cmd-open NativeFileDialog return path='NULL/취소' 매번 |cmd-open click _currentTwnPath='...' 첫/두번째 비교 |cmd-open click 로그 부재 |ApplyTwnPayload (외부) + ApplyTwnPayloadCore (내부) 분리. 외부에서 전체 catch.`csharp`Parts.ToDictionary(p => p.id) — 중복 시 ArgumentException -> silent`csharp`cmd-open click _currentTwnPath='{...}' — _currentTwnPath stuck 추적cmd-open NativeFileDialog return path='...' — 다이얼로그 반환값 추적[QA-044 진단] 라인 캡처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 신설 (기존 본체 분리)
ApplyTwnPayload (Bootstrap.cs:2323):byId.TryGetValue(p.id, ...) 매칭만 — payload.parts에 있는 부품만 처리BindRibbonFileNewCommand (Bootstrap.cs:1952):`csharp`ClearAllRuntimeComponents() 호출로 단순화. Vacuum 누락 자동 fix.Assets/Scripts/Game/Factory00Bootstrap.cs (+50라인)ClearAllRuntimeComponents() 신규 헬퍼 (50라인)ApplyTwnPayload 시작에 호출 추가 (1라인)ApplyTwnPayload Transform 복원 분기 (7라인)BindRibbonFileNewCommand 통일 (~20라인 -> 1라인)
_bus.OnBlowSignalChanged += OnBlowSignal 구독만, 해제 없음 -> Part 삭제 시 dead handler 누적.VacuumUnitActuator.Uninitialize() 메서드 신설 — _bus.OnBlowSignalChanged -= OnBlowSignalActuatorDriver.UnregisterActuator 안 if (actuator is VacuumUnitActuator vu) vu.Uninitialize() (옵션 B: type cast, IActuator 인터페이스 수정 없이 최소 변경)ActuatorDriver.UnregisterAll() 헬퍼 + OnDestroy 일괄 cleanupTransform _sceneRoot 선언만, 할당 없음 -> 항상 null -> SetParent(null) = 씬 루트._sceneRoot = null 명시적 default + 주석 "spec §3 SetParent(SceneRoot), factory00은 별도 SceneRoot GameObject 없음 -> null = Unity scene root (의도)". Ejector + Unit 양쪽.1f default, "1mm 흡착" 짧은 주석만.CommandBackward() { _blowSignal = true; /* 진공 유지 */ } -> CommandStop 후 재흡착 위험._vacuumSignal = false; _blowSignal = true; 명시. SetBlow/SetVacuum도 mutex 적용 (SetBlow(on) -> if (on) _vacuumSignal = false).IsChildOf(_parentPart.cachedTransform) 가드만 — pad가 Part 자식이 아닐 수 있음.if (go.transform == pad || go.transform.IsChildOf(pad)) continue; 추가. Ejector + Unit 양쪽.+= / -=) -> unsubscribe 경로 검증 의무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)spec-vs-codebase-pre-check.md) 갱신 — 이벤트 구독 패턴 검토 의무 추가
VacuumGraspedEvent (ActuatorId / Workpiece / Pad / PressureKpa / Timestamp)VacuumReleasedEvent (ActuatorId / Workpiece / PressureKpa / Reason / Timestamp)BlowSignalChangedEvent (ActuatorId / IsActive / Timestamp)VacuumReleaseReason enum (BlowSignalOn / VacuumOffDecay / AirBlowerEvent)OnVacuumGrasped / OnVacuumReleased / OnBlowSignalChanged 3 event_bus.OnBlowSignalChanged += OnBlowSignal 구독 — AirBlower 이벤트 수신 시 해제 (spec §3 시나리오)List VacuumEjectors List VacuumUnits List AirBlowers Assets/Scripts/Events/VacuumEvents.cs (신규 76라인)Assets/Scripts/Events/EventBus.cs (+12라인)Assets/Scripts/Actuators/VacuumActuators.cs (신규 275라인)Assets/Scripts/Core/Part.cs (+6라인)
`csharp`_partByTransform 제거하지만 _foldExpanded/_partHidden/_hiddenByParent dict 잔존 -> ListView fold/visibility 일관성 깨짐.`csharp`new Vector3(50f, 0, 0) (World Space) -> 회전된 부품 복제 시 예측 불가 방향.origGo.transform.right * 50f (Local X) -> 부모 회전 일관.Object.Destroy(comp)는 프레임 끝 실행 -> 같은 프레임 RebuildCacheAndUI 호출 시 stale Component 접근 위험.Object.DestroyImmediate(comp) 사용. Play Mode Component 대상 안전.Guid.NewGuid().ToString("N").Substring(0, 16) — 2^64 충돌 확률 충분.Assets/Scripts/Game/Factory00Bootstrap.cs (~25라인)DuplicateSelectedPart — leaf-only 가드 추가DuplicateCommand.Execute — Local X 오프셋 + GUID 16자DuplicateCommand.Undo — dict 3종 cleanupRemoveRuntimeComponents — DestroyImmediate 사용
Assets/Scripts/Game/Factory00Bootstrap.cs (+~125라인)DuplicateSelectedPart() 메서드 (line 6540 부근, VisibilityCommand 옆)DuplicateCommand : IEditCommand nested classObject.Instantiate(origGo, parent) + 위치 오프셋 50mm X + RemoveRuntimeComponents + 새 Part 객체 + Parts.Add + _partByTransform 갱신 + UI RebuildRemoveRuntimeComponents: Transform/MeshFilter/MeshRenderer/Collider 외 MonoBehaviour 전체 Destroyedit-duplicate 버튼 핸들러 = DuplicateSelectedPart 호출 (Placeholder 제거)Object.Instantiate 기본 sharedMesh 공유 |GetComponentsInChildren(true) — 전체 자식 GameObject 순회 |Update() line 3285 — ctrlEdit && !IsAnyTextFieldFocused() && KeyCode.D |_undoStack.ExecuteAndPush(new DuplicateCommand(this, target)) |{원본id}_copy_{GUID 8자} — 유일성 보장{원본name} (copy) — 부품 트리 직관적 표시Assets/Scripts/Game/Factory00Bootstrap.cs (+125라인)
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 버튼 = SSOTmodel-expand-all/model-collapse-all = 동일 람다 호출 (호환 유지)Assets/Scripts/Game/Factory00Bootstrap.csIsPartHidden(Part) — _partHidden dict 조회PickPartUnderMouse (line 3818):IsPartHidden(pp) -> return nullPerformDragSelect — 별도 가드 불필요 (r.enabled 체크가 이미 hide 부품 skip)Assets/UI/MainHUD.uxml (+5라인) — parts-toolbar 신설Assets/Scripts/Game/Factory00Bootstrap.cs (+25라인) — expand/collapse 람다 + IsPartHidden 가드
ribbon-tabs에만 WheelEvent StopPropagation 등록 (v0.1.170 line 1368~1382).ribbon-commands(60px 명령 영역) 위 휠은 명시적 차단 없음 -> propagation 거쳐 viewport zoom trigger.ribbon-commands 전체에 WheelEvent TrickleDown 콜백 등록.ribbon-tabs 전용 유지 (사용자 명령 영역에서 탭 전환은 비의도)`csharp`Input.GetMouseButtonDown(0) 분기 line 3013~):``overUI=true 항상 (좌표 무관) |ribbonH≠84 또는 inViewport 계산 오류 |overGizmo=true 항상 |leftW=Screen.width-N |[QA-014 진단] 패턴 그대로. View Tab 검증 시 함께 회신 부탁.Assets/Scripts/Game/Factory00Bootstrap.cs (+15라인)ribbonCommands.RegisterCallback 추가[QA-006 진단] LMB_DOWN 로그 1줄
[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%LOCALAPPDATA%LowDefaultCompanyactory00Player.log 확인[QA-014 진단] 라인 결과 handshake.md 답변 칸 회신ENTRY 로그 자체 부재 |Button '...' NOT FOUND 출력 |View click 부재 |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)
[2] yaw=45° pitch=30° dist=8.5 · 2026-05-17 22:00string savedAt — ISO8601 datetime (yyyy-MM-ddTHH:mm)JsonUtility 호환 — 기존 5 slot 데이터 손실 없음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 분기 추가
factory00.license.tier <- period 사용 (다른 키와 불일치)factory00.license_tier <- underscore SSOT 일관성migrated legacy key '...license.tier' -> '...license_tier' (tier=N))``Assets/Scripts/License/LicenseTier.cs (~15라인)PrefsKey = factory00.license_tier (변경)PrefsKeyLegacy = factory00.license.tier (신규 폐기 예정 const)Load() 안 마이그레이션 분기 (HasKey check + SetInt + DeleteKey + Save)
[2] yaw=45° pitch=30° dist=8.5) hover/click -> sub-menu 펼침덮어쓰기 (기존 SaveViewSlot) · 삭제 (PlayerPrefs.DeleteKey)[3] 비어있음) -> 단순 click = 저장 (기존 동작 유지)DeleteViewSlot(int slotN) — PlayerPrefs.DeleteKey + active slot 트래킹 reset (해당 slot 이 _activeViewSlot 일 때만) + 토스트Assets/Scripts/Game/Factory00Bootstrap.cs (~35라인)ShowViewSlotMenu Save 모드 분기에 parsed != null 조건 sub-menu 추가DeleteViewSlot(int) 헬퍼 신규
factory00.* prefix 키 12종 사용 (Bootstrap + SettingsVM + LicenseTier)factory00.parts_rows_height / factory00.inspector_height (READ-only)ViewSlot1Pref (참조 0건)factory00.license.tier (period 사용, 다른 키는 underscore) -> 마이그레이션 위험으로 보고만Assets/Scripts/Game/Factory00Bootstrap.cs (~3라인)ViewSlot1Pref const 제거 (호환 보존 주석은 ViewSlotPrefix 위치로 통합)partsRowsHeight <- factory00.parts_section_heightinspectorHeight <- factory00.inspector_section_height
View:[2] 형태로 우측 영역 표시_activeViewSlot 트래킹 (0 = 표시 없음, 1~5 = 마지막 슬롯)View:[2]. Load View slot 4 -> View:[4]Assets/Scripts/Game/Factory00Bootstrap.cs (~5라인)int _activeViewSlot = 0; 필드 신규_activeViewSlot = slotN; UpdateStatusLabel();slotLabel 분기 추가
[1] 비어있음 또는 [2] yaw=45° pitch=30° dist=8.5Load View: 저장된 slot 없음 (Save View 먼저)factory00.view_slot{1~5} (JSON 5개)ShowViewSlotMenu(Button anchor, bool isSave) 헬퍼 — Save/Load 동일 패턴SaveViewSlot(int) / LoadViewSlot(int) 헬퍼 — 단일 slot 처리Assets/UI/Components/Ribbon.uxml — Save/Load View tooltip 갱신Assets/Scripts/Game/Factory00Bootstrap.cs (~80 라인)ViewSlotPrefix / ViewSlotMax = 5 constantsShowViewSlotMenu / SaveViewSlot / LoadViewSlot 헬퍼ShowViewSlotMenu 호출로 단순화ViewSlot1Pref constant 보존 (v0.1.227 저장 데이터 호환)
View 저장 (slot 1): yaw=45° pitch=30° dist=8.5 / View 복원 (slot 1): ...Load View: slot 1 비어있음 (Save View 먼저)[System.Serializable] ViewState 클래스 — Unity JsonUtility 호환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.uxml — view-save + view-load 버튼Assets/Scripts/Game/Factory00Bootstrap.cs (~30 라인) — 핸들러 2개 + ViewSlot1Pref constant
OpenTwnPath(path) 호출최근 파일 없음 (.twn Open/Save 후 누적) 토스트factory00.recent_files (| separator, 최대 5개)LoadRecentFiles(): PlayerPrefs split + System.IO.File.Exists 필터 (삭제된 경로 자동 제외)AddToRecent(path): 중복 제거 + prepend + 최대 5개 + PlayerPrefs.SaveOpenTwnPath(string path) 신규 — cmd-open 핸들러 핵심 로직 추출try/catch + Load + ApplyTwnPayload + AddToRecent + Bus.Publish(TwnProjectLoadedEvent) 일원화Assets/UI/Components/Ribbon.uxml — cmd-recent 버튼 (Open 옆)Assets/Scripts/Game/Factory00Bootstrap.cs (~80 라인)OpenTwnPath(string path) 신규 (cmd-open 핸들러에서 추출)LoadRecentFiles() / AddToRecent(path) 헬퍼BindRibbonFileRecentCommand(root) 핸들러 (ContextMenuElement 표시)AddToRecent(path) 추가
Input.GetKey(LeftControl/RightControl) 가드 + KeyCode.A. TextField focus 시 입력 우선SelectAllParts() 신규 헬퍼 (Drag-select 패턴 미러 L6055~6072)Select All: N개 부품 선택 / 부품 없음 = Select All: 부품 없음Assets/UI/Components/Ribbon.uxml — edit-select-all tooltip 갱신 (v0.1.176 예정 -> Ctrl+A)Assets/Scripts/Game/Factory00Bootstrap.cs (~25 라인)edit-select-all placeholder 제거 -> () => SelectAllParts() 핸들러SelectAllParts() 메서드 신규v0.1.176 예정 -> 미구현 (Part Mesh/Material 복제 매트릭스 필요))
CommandHome() 호출ActuatorDriver.AllActuators 전수 순회 (IReadOnlyListActuatorState.HomingReturn -> HomePosition/0° 까지 자동 이동CommandBackward() (강제 후진)Stop: N Actuator Home 복귀 또는 Stop: N Actuator Home 복귀 (Pause 상태 — Resume 후 진행)Assets/UI/Components/Ribbon.uxml — sim-stop 버튼 추가Assets/Scripts/Game/Factory00Bootstrap.cs (~10 라인) — 핸들러CommandHome() 표준 명령. 3 타입 모두 구현 완료ServoAxisActuator.CommandHome() -> state=HomingReturn -> HomePosition 까지 _maxVelocityRotaryActuatorActuator.CommandHome() -> state=HomingReturn -> 0° wrap-awarePneumaticCylinderActuator.CommandHome() -> CommandBackward() (B포트)
Time.timeScale 0/1 토글Time.timeScale = 0 -> Actuator UpdateActuator + Sensor polling 모두 정지 (deltaTime 기반)Time.timeScale = 1 -> 정상 진행시뮬레이션 일시정지 (timeScale=0) / 시뮬레이션 재개 (timeScale=1)Assets/UI/Components/Ribbon.uxml — sim-pause-toggle 버튼 추가Assets/Scripts/Game/Factory00Bootstrap.cs (~12 라인) — 핸들러
ComputePartBounds 헬퍼 재사용 (Measure / Angle 와 동일 SSOT)Bounds.Intersects() AABB 빠른 검사. Physics.OverlapBox 미사용 (collider 의존성 회피)[review-collision] HIT {name1} ↔ {name2} 매 쌍 인용 + 합계충돌: 2+ 부품 선택 필요 (현재 N개)충돌: 부품 mesh 없음충돌: 0/N쌍 겹침충돌: 5/10쌍 — MotorA↔BracketB, MotorA↔CoverC, BracketB↔ShaftD 외Assets/UI/Components/Ribbon.uxml — review-collision 버튼 + P4 placeholder 제거Assets/Scripts/Game/Factory00Bootstrap.cs (~40 라인)review-collision 핸들러 (pairwise 이중 루프 + Bounds.Intersects)
PneumaticCylinderActuator 1개 부착Pneumatic 추가: N 부착 · M skip (이미 부착 또는 Servo/Rotary)RotaryActuator 1개 부착Rotary 추가: N 부착 · M skip (이미 부착 또는 Servo)공압 실린더 추가: PNC-{PartId}-001 / 회전 구동부 추가: ROT-{PartId}-001)Assets/UI/Components/Ribbon.uxml — model-add-pneumatic + model-add-rotary 버튼 (P2.3 placeholder 제거)Assets/Scripts/Game/Factory00Bootstrap.cs (~40 라인)model-add-pneumatic 핸들러 (3중 가드)model-add-rotary 핸들러 (2중 가드)
ServoAxisActuator 1개 부착AddServoAxisToPart 헬퍼 재사용 (Inspector Servo 추가 패턴 동일)구동부 추가: AXIS-{PartId}-001 (헬퍼 자체 토스트)Servo 추가: N 부착 · M skip (이미 부착 또는 Rotary)Add Servo: 이미 부착 또는 Rotary 와 동시 부착 불가Assets/UI/Components/Ribbon.uxml — model-add-servo 버튼 + P2.3 placeholder 갱신Assets/Scripts/Game/Factory00Bootstrap.cs (~20 라인)model-add-servo 핸들러 추가 (foreach selectedParts + 가드 분기)
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]}")Debug.Log("Init 완료") — 1회 lifecycle 표준Assets/Scripts/UI/SettingsPanelViewModel.cs 3 라인 (-3)ProjectSettings/ProjectSettings.asset bundleVersion 0.1.218 -> 0.1.219
GearMouseDownCount / GearClickedCount / EscEventCount / ToggleCallCount 카운터 필드 4종OnDiagnostic 콜백 인프라_toggleBtn.clicked += Toggle; 단순화#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.217GearMouseDownCount|GearClickedCount|EscEventCount|ToggleCallCount|FocusInCount|FocusOutCount|EscKeyCount|MouseDownCount|OnDiagnostic — Bootstrap/SettingsVM/SearchVM 3 파일 0건
GearMouseDownCount / GearClickedCount / EscEventCount / ToggleCallCount 카운터 필드 4종OnDiagnostic 콜백 인프라_toggleBtn.clicked += Toggle; 단순화#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.217GearMouseDownCount|GearClickedCount|EscEventCount|ToggleCallCount|FocusInCount|FocusOutCount|EscKeyCount|MouseDownCount|OnDiagnostic — Bootstrap/SettingsVM/SearchVM 3 파일 0건
FlashToast($"{k} keydown tf={tf} input='{searchInput}'") 발화Debug.Log("[input] MouseDown(L) screen=...") 발화FocusInCount / FocusOutCount / EscKeyCount / MouseDownCount 카운터 필드 제거OnDiagnostic 콜백 인프라 제거_host.RegisterCallback)OnDiagnostic?.Invoke + Debug.Log 삭제 (UI 동작은 보존)#if DEBUG _searchVM.OnDiagnostic = ... wire 제거#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_input / OnInputChanged / OnEnterPressed / OnEscapeWhileFocused / IME 처리_settingsVM.OnDiagnostic = ... wire 자체가 #if DEBUG 가드. production strip. 본 사이클 범위 외
_autoDiagFired 1회 발화 splitter+axis 자동 진단-qa CLI 플래그) — 5초 후 search field에 "motor" 자동 입력 데모-gizmo-rotate CLI — autoSelectFirstMotor 직후 Gizmo Rotate 모드 강제 (G 키 PostMessage 우회용)DebugSplitterDelta / DebugAxisDragSimulate / DebugSimulateDragSelectInViewport / DebugSimulateDragSelectOverPanel_autoDiagFired · _autoSearchTriggered · _autoSearchTimer · _gizmoStartRotate · autoTypeSearch · autoTypeSearchQuery · autoTypeSearchDelaySec-capture-now — capture-unity-1920.sh 메인 trigger-capture-delay — 모델 로딩 대기-capture-exit — 캡처 후 자동 종료-qa-out — 캡처 저장 경로 overrideqaCaptureDir 필드 — 위 CLI 처리에서 사용Assets/Scripts/Game/Factory00Bootstrap.cs 6622 -> 6471 라인 (-151)_gizmoStartRotate 사용 1건 제거Assets/Scripts/UI/SearchWidgetViewModel.cs 주석 1줄 갱신 (autoQA / autoTypeSearch 표현 제거)-capture-now / -capture-delay / -capture-exit / -qa-out 4 CLI 그대로 동작. 영향 0-qa / -gizmo-rotate 사용 안 함. 영향 0
PhotoSensorComponent 1개 부착AddPhotoSensorToPart 헬퍼 재사용 (이미 Inspector Sensor Remove 옆 패턴 존재)센서 추가: SENSOR-{PartId}-{seq})[MotorA] Sensor 1 · Servo 1 / [Bracket] None (컴포넌트 미부착)Component: Sensor 3 · Servo 2 · Rotary 0 · Pneumatic 1 · None 4Assets/UI/Components/Ribbon.uxml — model-add-sensor 버튼 추가 + P2.2 placeholderAssets/Scripts/Game/Factory00Bootstrap.cs (~30라인)model-component-info 핸들러 단일/다중 분기 추가model-add-sensor 핸들러 추가 (foreach selectedParts -> AddPhotoSensorToPart)
Component: Sensor 2 · Servo 1 · Rotary 0 · Pneumatic 0 · None 5Assets/UI/Components/Ribbon.uxml — cmds-model 영역에 model-component-info 버튼 + tooltipAssets/Scripts/Game/Factory00Bootstrap.cs (~20라인) — clicked 핸들러 + 컴포넌트 분포 카운트Tools/qa/build-and-publish.sh (신규) — Unity 빌드 + dll 검증 + 자동 재빌드 + publish
Mathf.Atan2(dy, dx) -> 0~360°Mathf.Atan2(dz, √(dx²+dy²)) -> -90~+90°각도: XY 45.0° / Z경사 +12.3°AUTO-TOC-START / AUTO-TOC-END marker 신설 (publish-gallery.sh 안 python3 정규식 추출).toc 스타일 (배경 + flex-wrap + hover 골드 톤)Assets/UI/Components/Ribbon.uxml — cmds-review 영역에 review-angle 버튼 + tooltipAssets/Scripts/Game/Factory00Bootstrap.cs (~25라인) — clicked 핸들러 + 수평/수직 각도 분해wiki/publish-gallery.sh — TOC marker inject + python3 인덱스 재생성 + CSS 신규
RunInterfaceEmulationDemo() 코루틴 시작 (F12 키와 동등)시나리오 이미 실행 중 안내 토스트 (중복 시작 방지) - (2칸) -> - (margin-left 24px), - (4칸) -> - (margin-left 32px) 들여쓰기 hierarchy 표시 - review-measure 같은 sub-item이 평문으로 들어가던 결함 fixAssets/UI/Components/Ribbon.uxml — cmds-present 영역에 present-scenario-play 버튼 추가Assets/Scripts/Game/Factory00Bootstrap.cs (~12라인) — clicked 핸들러 + 중복 실행 가드Tools/qa/publish-build-auto.sh — markdown 변환 case 추가 ( - / - 패턴)
Bounds.center) 사이 거리 + Δ(x,y,z) mm 토스트측정: 정확히 2개 선택 필요 (현재 N개) 안내 토스트측정: 부품 mesh 없음 토스트Assets/UI/Components/Ribbon.uxml — cmds-review 영역에 review-measure 버튼 + tooltip + P3 placeholderAssets/Scripts/Game/Factory00Bootstrap.cs (~30라인)review-measure clicked 핸들러 (2부품 가드 + Sqrt 거리 계산 + 토스트)Bounds? ComputePartBounds(Part p) (Renderer.bounds 합집합)ComputeAllPartsBounds() 리팩토링 (신규 헬퍼 재사용 — 코드 -12라인 +6라인)Renderer.bounds.center 직접 사용 -> 결과 mm거리: 1234.5mm Δ(100.0, 200.0, 300.0) 1자리 소수





















































































































































































