diff --git a/.claude/skills/analyze-ptop-architecture/SKILL.md b/.claude/skills/analyze-ptop-architecture/SKILL.md deleted file mode 100644 index e5c0e8a..0000000 --- a/.claude/skills/analyze-ptop-architecture/SKILL.md +++ /dev/null @@ -1,200 +0,0 @@ ---- -name: analyze-ptop-architecture -description: ILSOS_PrismaticRD_PTOP의 3계층 아키텍처(UI → Machine Logic → Device)를 분석하고 검증. EquipDef.cs, EquipmentSetup.cs, Sequences/, Device/ 폴더의 관계를 맵핑하고 Rx.NET 이벤트 흐름을 추적. 디바이스 스택(PLC, Laser, OCT, CellTracker) 통합 여부 검증. "PTOP 아키텍처 분석", "PTOP 계층 구조 검토", "디바이스 스택 파악" 처럼 **구조·의존성 한 영역만** 볼 때 쓴다. 구분 — 아키텍처·구현·빌드를 함께 보려는 요청("PTOP 전체 점검", "종합 분석", "구조 파악")은 `orchestrate-ptop-harness`를 쓴다. 맨손 "업데이트"·"다시 실행"만으로는 이 스킬을 고르지 않는다 — 대상을 먼저 확인한다. ---- - -# Analyze PTOP Architecture Skill - -## 목표 - -ILSOS_PrismaticRD_PTOP의 **3계층 아키텍처 전체 그림**을 명확히 파악하고 문서화한다. - -## 분석 단계 -> **소스 루트 = `Machines/ILSOS_PrismaticRD_PTOP/`.** 이 문서의 상대 경로(`Sequences/…`, -> `Device/PLC/…`)는 모두 그 아래다. 저장소 루트의 동명 폴더 `ILSOS_PrismaticRD_PTOP/`은 -> 빌드 산출물(.pdb)이므로 거기서 소스를 찾지 말 것. - - -### 1단계: EquipDef.cs & EquipmentSetup.cs 분석 - -**EquipDef.cs에서 수집할 항목:** -- `DeviceIds : CommonDeviceIds`에 **직접 선언된** 상수 (`MassFlowMeter` 등) + base에서 상속된 것 -- `SequenceIds : CommonSequenceIds`에 **직접 선언된** 상수 — - `SeqStreamTest`, `SeqEventQTest`, `SeqTestRun`, `SeqAutoRunComponentWeld`, `SeqAlarmMonitor`, - `SeqStatusMonitor`, `SeqAutoRunTDC`, `SeqAutoRunPTOP` (8개) -- 커스텀 `DeviceIds` / `SequenceIds` / `SettingIds` / `StreamMessageNames` - (`MotorIds`·`RecipeIds` 클래스는 **없다** — base `Common*`·레시피 매니저가 관리) - -**EquipmentSetup.cs에서 수집할 항목:** -- `GetEquipmentName()` → 장비명 확인 ("ILSOS PrismaticRD_PTOP") -- `BuildMainStatusView()` → 표시되는 디바이스 (CellTracker, OCT) -- `OnSetAlarm()` 로직 → 알람 처리 -- `OnStartUp()` 로직 → 초기화 순서 -- SequenceBuilder 선언과 **실제 `register(...)` 여부는 다르다.** `EquipmentSetup.cs:206-218` 기준: - - `_SeqAutoRunPrismatic_Builder` → **등록됨**(`:211`, `SequenceIds.SeqAutoRun`) - - `_SeqAutoRunComponentWeld_Builder` → 대입은 되나 **등록 주석 처리**(`:212`) - - `_SeqTestRun_Builder` → **선언만·대입 없음**, 등록도 주석(`:213`) - - `_SeqAlarmMonitor_Builder` → **등록됨**(`:214`) - - `SeqStatusMonitor.Builder()` → **필드 없이 직접 등록됨**(`:215`) — 빌더 필드만 보면 놓친다 - - `_SeqAutoRunPTOP_Builder` → **등록됨**(`:218`), 메인 시퀀스 (260605) - - > 목록을 그대로 옮기지 말고 **작업 전 `register(` 호출부를 실제로 나열해 대조하라** — - > 주석 처리 여부까지 확인해야 "빌드되는 시퀀스"를 정확히 말할 수 있다. - -**출력:** `_workspace/01a_equipdef_analysis.md` - -### 2단계: Sequences/ 폴더 구조 분석 - -**주요 파일들:** -``` -Sequences/ -├── SeqAutoRunPTOP.cs ← 메인 (분석 우선순위 1, 260605) -├── SeqAutoRunPrismatic.cs ← 기존 (2026-06-18에 SeqAutoRunPrismaticScanner에서 개명) -├── SeqAutoRunComponentWeld.cs -├── SeqTestRun.cs -├── SeqStreamTest.cs -├── SeqEventQTest.cs -├── SeqWaitWeldOrChangePage.cs -├── LaserAngleOffsetSelector.cs -├── SequenceContextEx.cs ← 컨텍스트 정의 -├── SequenceManager.cs ← 시퀀스 관리 -├── Monitoring/ -└── Manual/ -``` - -> 트리는 참고용이다. **작업 전 `Sequences/`를 실제로 나열해 대조하라** — 이 목록이 낡았을 수 있다. - -**각 시퀀스 분석 항목:** -- 용도 (주 시퀀스? 테스트? 모니터링?) -- 상태 머신 정의 (시작, 대기, 실행, 완료, 에러) -- 타이밍 (예상 소요시간) -- 호출하는 디바이스 목록 -- 의존성 (다른 시퀀스에 의존하는가?) - -**특히 SeqAutoRunPTOP.cs:** -- 상태 다이어그램 작성 -- 각 상태에서 호출되는 디바이스/API 추적 -- 타임아웃/재시도 로직 - -**출력:** `_workspace/01b_sequences_analysis.md` - -### 3단계: Device/ 폴더 분석 - -**파일 구조:** -``` -Device/ -├── PLC/ -│ ├── PLCContoller.Config.cs ← 생성자·접속 설정만. 18줄, 주소 0건 (Controller 아님 — 저장소 오탈자) -│ ├── PLCController.Logic.cs ← 읽기/쓰기 로직 -│ └── PLCController.Address.cs ← PLC 주소 맵의 진실원. 신호 상수 enum -└── IO/ - └── PAIX_PTOP.cs ← IO 제어 (2026-06-18 개명) -``` - -> **동명 심볼 함정.** `WeldingCommon.Devices.Laser.PAIX_PrismaticScanner`(공유)와 -> `WeldingComponents/WeldingCommon/Devices/PLC/PLCController.Config.cs`(공유, 오탈자 없음)는 -> 개명되지 않고 그대로 존재한다. 머신 쪽 파일과 혼동하지 말 것. - -**PLC 분석:** (모든 값은 `PLCController.Address.cs`의 enum에서 읽어 `파일:라인`과 함께 적는다) -- 실제 사용되는 주소 범위 — 추정하지 말고 enum 정의에서 확인 -- 주요 신호 목록 (eBitInput/eBitOutput/eWordInput/eWordOutput) -- 읽기·쓰기 주기, 타임아웃 — 코드 상수 기준. 못 찾으면 `불명확 — 확인 필요` - -**IO 분석:** -- 입력 신호 (센서, 스위치) -- 출력 신호 (제어 신호) -- 각 신호의 의미 - -**출력:** `_workspace/01c_device_analysis.md` - -### 4단계: Rx.NET 이벤트 흐름 분석 - -**수집할 정보:** -- System.Reactive 사용 패턴 (Observable, Subject, etc.) -- 메시지 타입 (String/Double/Int/JSON/LBAD) -- 구독자 목록 (누가 어떤 메시지를 구독?) -- 백프레셔/에러 처리 - -**파이프라인 예시:** -``` -[PLC Status] Observable - ├─→ Filter(Ready == true) - ├─→ Select(x => new LaserCommand()) - └─→ Subscribe(Laser.Execute()) -``` - -**출력:** `_workspace/01d_rxnet_analysis.md` - -### 5단계: 외부 디바이스 통합 검증 - -**검증 대상:** -- PLC (Mitsubishi) -- Laser (AuroraLaser) -- OCT Scanner (AuroraOCT) -- CellTracker (AuroraCellTracker) -- IO (PAIX) - -**각 디바이스마다:** -- 초기화 시점 -- 활성화 조건 -- 사용 방식 (동기/비동기) -- 에러 처리 -- 정상 종료 절차 - -**출력:** `_workspace/01e_device_integration.md` - -## 통합 산출물 - -### 최종 보고서: `_workspace/01_ptop_architecture.md` - -보고서 골격은 [references/report-template.md](references/report-template.md) 참조. -모든 항목에 `파일:라인` 근거를 붙이고, 확인 못 한 내용은 `불명확 — 확인 필요`로 남긴다. - -**단독 기동으로 `01`을 갱신했으면 stale 표기 의무는 여전히 네게 있다.** "아키텍처만 다시" 같은 요청은 -이 스킬로도, `orchestrate-ptop-harness`로도 들어올 수 있는데 오케스트레이터 경유가 아니면 표기해 줄 주체가 없다. -`01`의 첫 줄에 `이번 실행에서 갱신됨(YYYY-MM-DD)` 을 적고, **이 파일에 의존하는 `02`·`03`이 이미 있으면** -그 두 파일 첫 줄에 `이전 실행 결과 재사용 — 01 갱신으로 정합성 미확인(YYYY-MM-DD)` 을 남긴다 -(문구 3종 → `orchestrate-ptop-harness/references/data-protocol.md`). -**코드로 확인하지 않은 인과·해석은 문장 앞에 `[추론]`을 붙인다** (`rules.md` #15·#16). -`불명확 — 확인 필요`(값을 못 찾음)와 축이 다르니 대체하지 말고 필요하면 병기한다. -확인한 뒤에는 `[추론]`을 떼고 `파일:라인`으로 바꾼다. - -## 입력 조건 -> **단독 호출 시**: 생성할 `_workspace/` 파일 목록을 사용자에게 제시하고 승인받은 뒤 시작한다 -> (`rules.md` #2). 오케스트레이터(`orchestrate-ptop-harness`)를 통해 호출된 경우는 이미 승인을 받았으므로 생략한다. - - -사용자가 다음과 같이 요청할 때: -- "PTOP 아키텍처 분석해줘" -- "PTOP 계층 구조 검토" -- "PTOP에서 PLC, Laser, OCT가 어떻게 연결되어있는지" -- "PTOP 3계층 아키텍처 검증" - -> "PTOP 전체 점검"·"종합 분석"처럼 **구현·빌드까지 함께** 보려는 요청은 이 스킬이 아니라 -> `orchestrate-ptop-harness`다. 시퀀스 내부 동작만이면 `analyze-ptop-implementation`, -> 빌드/CI면 `optimize-ptop-build`. - -## 출력 결과 - -- 5개 상세 분석 문서 (`_workspace/01a~01e_*.md`) -- 통합 보고서 (`_workspace/01_ptop_architecture.md`) -- 다이어그램 (3계층, 상태 머신, 이벤트 흐름) - -## 주의사항 - -1. **코드 읽기 능력이 중요** — C#, WPF, Rx.NET 이해 필수 -2. **불명확한 부분은 기록** — "이 부분은 왜 이렇게?"라는 질문을 명시 -3. **Namespace** — 대부분 `ILSOS_PrismaticRD_PTOP.*`이고 옛 `ILSOS_PrismaticScanner`는 0건이다. - 단 **프로젝트 내 예외 3개**: `Sequences/SeqTestRun.cs:35`=`ILSOS_PrismaticRD_TDC.Sequences`, - `Sequences/Monitoring/SeqAlarmMonitor.cs:22`·`SeqStatusMonitor.cs:11`=`WeldingCommon.Sequences`. - 네임스페이스로 grep하면 이 3개가 누락된다 — 파일 경로로 찾을 것. - 또한 **공유 프로젝트에는 `PAIX_PrismaticScanner` 같은 옛 이름 심볼이 그대로 남아 있으니** 머신 심볼과 혼동 금지 -4. **260605 변경 이후 상태 파악** — SeqAutoRunPTOP이 최신 메인 시퀀스 -5. **한글 주석 인코딩** — `docs/CODING_RULES.md` 확인 -6. **주석·변수명·함수명을 맹신하지 않는다** (`rules.md` #1) — 위 3의 `PAIX_PrismaticScanner` 잔존이 - 그 사례다. 이름이 계층·소속을 말해 주지 않으므로 등록부·구현 본문으로 확인한다. - -> 이 스킬은 10분을 넘긴다 — **단계 전환마다 지금 어느 단계인지 한 줄로 보고한다**(`rules.md` #10). -> -> 단독 호출로 마무리할 때: 보고는 `rules.md` #11~13 출력 형식(수정 줄=초록 화살표, 단어=주황, 미변경=기본색)을 -> 따르고, 끝에 관련 `.md`를 갱신할 부분이 있는지 묻는다(`rules.md` #6). diff --git a/.claude/skills/analyze-ptop-architecture/references/report-template.md b/.claude/skills/analyze-ptop-architecture/references/report-template.md deleted file mode 100644 index b0d4c56..0000000 --- a/.claude/skills/analyze-ptop-architecture/references/report-template.md +++ /dev/null @@ -1,63 +0,0 @@ -# 보고서 템플릿 — `_workspace/01_ptop_architecture.md` - -> 이 골격을 채워 통합 보고서를 만든다. **모든 항목에 `파일:라인` 근거를 붙인다.** -> 코드에서 확인하지 못한 내용은 비워두지 말고 `불명확 — 확인 필요`로 적는다. - -```markdown -# ILSOS_PrismaticRD_PTOP 아키텍처 검토 보고서 - -## 1. 3계층 아키텍처 - -┌──────────────────────────────┐ -│ WPF UI Layer │ -│ (Views/, ViewModels/) │ -└──────────────┬───────────────┘ - ↓ -┌──────────────────────────────┐ -│ Machine Logic Layer │ -│ (EquipmentSetup, Sequences) │ -└──────────────┬───────────────┘ - ↓ -┌──────────────────────────────┐ -│ Device Abstraction │ -│ (AuroraDevices) │ -└──────────────┬───────────────┘ - ↓ -┌──────────────────────────────┐ -│ Hardware Layer │ -│ (PLC, Laser, OCT, etc.) │ -└──────────────────────────────┘ - -계층 경계 위반 지점: <파일:라인> — <어느 계층이 어느 계층을 건너뛰는가> - -## 2. 핵심 컴포넌트 - -### EquipDef & EquipmentSetup -- EquipDef 매핑 표 — 출처: `EquipDef.cs:<라인>` -- 등록되는 시퀀스 목록 — 출처: `EquipmentSetup.cs:<라인>` - -### Sequences -- 시퀀스 관계도 (활성/비활성 표시) -- SeqAutoRunPTOP 상태 머신 — 출처: `Sequences/SeqAutoRunPTOP.cs:<라인>` - -### Device -- PLC 신호 맵핑 — 출처: `Device/PLC/PLCController.Address.cs:<라인>` -- IO 신호 맵핑 — 출처: `Device/IO/PAIX_PTOP.cs:<라인>` - -## 3. Rx.NET 이벤트 흐름 - -<발행 지점 → 필터 → 구독 지점 파이프라인. 각 단계에 파일:라인> - -## 4. 발견 사항 & 개선 사항 - -| 우선순위 | 항목 | 현황(근거 파일:라인) | 개선안 | -|---------|------|------|--------| -| P0 | | | | -| P1 | | | | -| P2 | | | | - -## 5. 불명확 — 확인 필요 - -| 항목 | 왜 확인 못 했는가 | 무엇을 보면 확정되는가 | -|---|---|---| -``` diff --git a/.claude/skills/analyze-ptop-implementation/SKILL.md b/.claude/skills/analyze-ptop-implementation/SKILL.md deleted file mode 100644 index 66f014e..0000000 --- a/.claude/skills/analyze-ptop-implementation/SKILL.md +++ /dev/null @@ -1,183 +0,0 @@ ---- -name: analyze-ptop-implementation -description: ILSOS_PrismaticRD_PTOP의 구현 상세 분석. SeqAutoRunPTOP 시퀀스 로직, PLC/Laser/OCT/CellTracker 디바이스 호출 흐름, Rx.NET 메시지 체인, 상태 전이, 타이밍, 에러 처리를 분석하고 구현 개선안 제시. "PTOP 시퀀스 로직 분석", "PLC 통신 흐름 추적", "디바이스 호출 순서", "타이밍 다이어그램" 요청 시 사용. 구분 — 계층·의존성 구조는 `analyze-ptop-architecture`, 빌드/CI는 `optimize-ptop-build`, 셋을 함께 보려는 종합 요청은 `orchestrate-ptop-harness`. 맨손 "업데이트"·"다시 실행"만으로는 이 스킬을 고르지 않는다 — 대상을 먼저 확인한다. ---- - -# Analyze PTOP Implementation Skill - -## 목표 - -ILSOS_PrismaticRD_PTOP의 **구현 세부사항**을 분석하고 최적화 기회를 식별한다. - -## 분석 영역 - -### 1단계: SeqAutoRunPTOP.cs 상태 머신 분석 - -**수집 대상:** -- 상태 정의 (enum/class로 표현된 상태들) -- 상태 진입 조건 -- 상태 내 액션 (동작) -- 상태 종료 조건 -- 상태 전이 경로 -- 타임아웃 설정 -- 재시도 로직 - -**산출 형식: 상태 다이어그램** -``` -[시작] - ↓ (전이 순서 — 시간축은 코드 상수 확인 후 기입) -[초기화] → [준비] → [용접] → [완료] → [정리] → [대기] - ↓ ↓ ↓ ↓ ↓ -[에러 처리] ← ← ← ← ← ← ← ← ← ← ← ← -``` - -### 2단계: 디바이스 호출 시퀀스 추적 - -각 상태에서: -- 어떤 디바이스가 호출되는가? -- 호출 순서는? (순차 vs 병렬) -- 예상 소요시간? -- 다음 상태로의 전이 신호는 어디서 오는가? - -**추적 대상:** -1. **PLC 호출** - - 실제 API·주소는 `Device/PLC/PLCController.Logic.cs`와 `PLCController.Address.cs`에서 확인한다. - PTOP은 원시 주소 문자열이 아니라 **enum 기반**(eBitInput/eBitOutput/eWordInput/eWordOutput)이다. - - 읽기 / 쓰기 / 폴링 지점을 각각 `파일:라인`과 함께 기록 - - 주소·API 이름을 기억이나 추측으로 쓰지 말 것 — 반드시 소스에서 확인한 것만 적는다. - -2. **Laser 제어** - - 활성화 (SetPower, SetFrequency, etc.) - - 대기 - - 정상 종료 - -3. **OCT 스캔** - - 스캔 시작 - - 데이터 수집 - - 스캔 종료 - -4. **CellTracker** - - 셀 추적 시작 - - 위치 업데이트 - - 추적 종료 - -**산출 형식: 타이밍 다이어그램** -``` -Time <코드 상수 기준 눈금 — 실측이 아니면 눈금 대신 순서만 표기> -State [<상태1>][<상태2>][<상태3>] -PLC <호출> <호출> -Laser <호출> -OCT <호출> -CellTrk <호출> -``` - -> 축의 숫자는 **코드에서 읽은 지연 상수**이거나 **실측값**일 때만 넣는다. -> 둘 다 아니면 눈금을 빼고 호출 순서만 그린다 — 없는 시간축을 그리면 병목 판단이 오염된다. - -### 3단계: Rx.NET 메시지 체인 분석 - -**수집 대상:** -- Observable 소스 (어디서 데이터가 나오는가?) -- 변환 (Select, Map, Filter) -- 구독자 (누가 소비하는가?) -- 에러 처리 (OnError, Catch) - -**기록 형식:** 실제 소스에서 발췌한 구독 체인을 그대로 인용하고 `파일:라인`을 붙인다. - -``` -<발행 지점> — 파일:라인 - └─ <연산자 체인> — 파일:라인 - └─ <구독 지점> — 파일:라인 -``` - -> 이 스킬은 예시 코드를 제공하지 않는다. Aurora의 실제 이벤트 API(`EventPublisher`/`EventObservable`)는 -> `docs/Aurora에이전트레퍼런스모음/01_concepts/event.md`에서 확인하고 저장소 코드로 대조하라. -> **그 폴더는 `.gitignore` 제외(로컬 전용)라 없을 수 있다** — 없으면 `External/Aurora/Aurora2.0_Guide.pdf`와 -> 소스 코드를 직접 대조한다. -> 그럴듯한 가짜 체인을 적으면 이후 분석이 통째로 그 위에 쌓인다. - -**산출 형식: 메시지 파이프라인 맵** - -### 4단계: 에러 처리 로직 - -**찾아야 할 패턴:** -- Try-Catch 블록 -- TimeoutException 처리 -- PLC 에러 응답 처리 -- 디바이스 오류 복구 -- 폴백 경로 (재시도, 초기화 재개, 강제 종료) - -**각 에러에 대해:** -- 감지 방법 -- 처리 방식 -- 복구 가능 여부 -- 사용자 개입 필요 여부 - -### 5단계: 성능/안정성 분석 - -**성능:** -- 각 상태의 예상 소요시간 -- 전체 시퀀스 총 소요시간 -- 병목 구간 (가장 오래 걸리는 부분) -- 최적화 기회 (병렬화 가능한가?) - -**안정성:** -- 데드락 가능성 (두 디바이스가 서로 대기?) -- 타이밍 이슈 (신호 도착 순서 의존?) -- 리소스 누수 (구독 취소 안 됨?) -- 상태 불일치 (PLC와 소프트웨어 상태 차이?) - -## 통합 산출물 - -### 최종 보고서: `_workspace/02_ptop_implementation.md` -(**필수 산출물 2종**: `_workspace/02_ptop_implementation.md` · `_workspace/03_device_integration.md`) - -보고서 골격은 [references/report-template.md](references/report-template.md) 참조. - -> **타이밍·주소·소요시간을 지어내지 않는다.** 코드 상수에서 읽은 값(`파일:라인` 병기)이나 -> 실측값만 적고, 둘 다 아니면 `미측정`이라고 쓴다. -> **상태 전이·경합·인과를 코드로 확인하지 않고 서술하면 문장 앞에 `[추론]`을 붙인다** -> (`rules.md` #15·#16). `미측정`(값 없음)과 축이 다르니 대체하지 말고 병기한다. -> 주석이 그렇게 쓰여 있다는 것은 확인이 아니다 (#1) — 실제 코드 경로를 따라가야 표기를 뗄 수 있다. - -## 입력 조건 -> **단독 호출 시**: 생성할 `_workspace/` 파일 목록을 사용자에게 제시하고 승인받은 뒤 시작한다 -> (`rules.md` #2). 오케스트레이터(`orchestrate-ptop-harness`)를 통해 호출된 경우는 이미 승인을 받았으므로 생략한다. - - -사용자가 다음 요청 시: -- "PTOP 시퀀스 로직 상세 분석" -- "SeqAutoRunPTOP이 PLC/Laser/OCT을 어떻게 제어하는가" -- "PTOP 타이밍 분석" -- "PTOP에서 에러가 발생하면 어떻게 처리되나" -- "PTOP의 성능 병목은" - -## 출력 결과 - -- 상태 머신 다이어그램 -- 타이밍 다이어그램 (시간축) -- Rx.NET 메시지 흐름도 -- 에러 처리 매트릭스 -- 성능 프로파일 -- 최종 분석 보고서 - -## 주의사항 - -1. **코드 라인 번호 기록** — "Line 245의 try-catch" 형식으로 정확한 위치 기록 -2. **데이터 흐름 추적** — 변수, 반환값을 따라가며 이해 -3. **시간 측정** — Thread.Sleep() / Task.Delay() / TimeSpan 찾기 -4. **예외 처리** — Exception 타입별로 분류 -5. **불명확한 부분 기록** — 추측 금지, 명시적으로 "불명확함" 표시 -6. **주석·변수명·함수명을 맹신하지 않는다** (`rules.md` #1) — 이름이 말하는 동작과 실제 구현이 - 다른 사례가 이 저장소에 실재한다. 판단 근거는 항상 구현 본문이다. - -> **단독 기동으로 `02`·`03`을 갱신했으면 stale 표기 의무는 네게 있다.** "구현만 다시" 같은 요청은 -> 이 스킬로도, `orchestrate-ptop-harness`로도 들어올 수 있는데 오케스트레이터 경유가 아니면 표기할 주체가 없다. -> 갱신한 파일 첫 줄에 `이번 실행에서 갱신됨(YYYY-MM-DD)` 을 적고, 의존 관계인 `01`이 낡았으면 -> `01` 첫 줄에 `이전 실행 결과 재사용 — 정합성 미확인(YYYY-MM-DD)` 을 남긴다 -> (문구 3종 → `orchestrate-ptop-harness/references/data-protocol.md`). - -> 이 스킬은 10분을 넘긴다 — **단계 전환마다 지금 어느 단계인지 한 줄로 보고한다**(`rules.md` #10). -> -> 단독 호출로 마무리할 때: 보고는 `rules.md` #11~13 출력 형식(수정 줄=초록 화살표, 단어=주황, 미변경=기본색)을 -> 따르고, 끝에 관련 `.md`를 갱신할 부분이 있는지 묻는다(`rules.md` #6). diff --git a/.claude/skills/analyze-ptop-implementation/references/report-template.md b/.claude/skills/analyze-ptop-implementation/references/report-template.md deleted file mode 100644 index 24833a3..0000000 --- a/.claude/skills/analyze-ptop-implementation/references/report-template.md +++ /dev/null @@ -1,56 +0,0 @@ -# 보고서 템플릿 — `_workspace/02_ptop_implementation.md` - -> 이 골격을 채워 통합 보고서를 만든다. -> -> **수치를 지어내지 않는다.** 타이밍·주소·소요시간은 두 가지만 허용한다 — -> ① 코드 상수에서 읽은 값(반드시 `파일:라인` 병기), ② 실제 측정값(측정 방법 병기). -> 둘 다 아니면 `미측정`이라고 쓴다. 아래 `<...>`는 전부 채워야 할 자리이며, -> 그럴듯한 예시 숫자로 메우면 이후 최적화 판단이 오염된다. - -```markdown -# PTOP 구현 분석 보고서 - -## 1. 상태 머신 - -<상태 목록 · 전이 조건 · 전이 트리거. 각 항목에 파일:라인> - -## 2. 디바이스 호출 시퀀스 - -### <상태A> → <상태B> 전이 -- <호출 순서 1>: — 출처: `<파일>:<라인>` -- <호출 순서 2>: — 출처: `<파일>:<라인>` -- 전이 조건: <조건> — 출처: `<파일>:<라인>` - -| 단계 | 디바이스 | 호출 | 지연 상수 | 출처(파일:라인) | -|---|---|---|---|---| -| | | | 코드값 또는 `미측정` | | - -## 3. Rx.NET 메시지 흐름 - -<발행 → 필터 → 변환 → 구독 파이프라인. 각 단계 파일:라인> - -## 4. 에러 처리 - -| 에러 유형 | 감지 방법 | 처리 방식 | 복구 가능 | 출처(파일:라인) | -|---------|---------|---------|---------|---| - -## 5. 성능 프로파일 - -| 구간 | 소요시간 | 근거(코드 상수 / 실측 / 미측정) | 최적화 기회 | -|------|---------|---|----------| - -> 실제로 측정하지 않았다면 소요시간 칸에 `미측정`이라고 쓴다. - -## 6. 발견 사항 - -### P0 (심각) -- <내용> — 근거: `<파일>:<라인>` - -### P1 (중요) -### P2 (개선) - -## 7. 불명확 — 확인 필요 - -| 항목 | 왜 확인 못 했는가 | 무엇을 보면 확정되는가 | -|---|---|---| -``` diff --git a/.claude/skills/claudeskills_260630_ndy.zip b/.claude/skills/claudeskills_260630_ndy.zip deleted file mode 100644 index e4cc4ca..0000000 Binary files a/.claude/skills/claudeskills_260630_ndy.zip and /dev/null differ diff --git a/.claude/skills/doyeon_note/SKILL.md b/.claude/skills/doyeon_note/SKILL.md deleted file mode 100644 index fa28229..0000000 --- a/.claude/skills/doyeon_note/SKILL.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -name: doyeon_note -description: 도연님의 작업일지를 기록합니다. "/doyeon_note <내용>" 형태로 호출하면 docs/작업일지/yyyy_mm_dd.md 파일에 오늘 날짜로 내용을 추가합니다. 작업일지 기록, 일지 작성, 노트 추가 요청 시 사용. 구분 — 결과를 PaJu todolist 사이트에 게시하는 것은 `todo-summary`, 이 스킬은 `docs/작업일지/` 로컬 md 기록 전용이다. ---- - -# doyeon_note — 작업일지 기록 스킬 - -사용자가 말한 내용을 `docs/작업일지/yyyy_mm_dd.md` 파일에 기록합니다. - -## 동작 절차 - -1. **오늘 날짜 확인**: 시스템의 현재 날짜를 `yyyy_mm_dd` 형식으로 만든다. - (컨텍스트에 `currentDate`가 있으면 그 값을 사용. 없으면 `date +%Y_%m_%d` 실행) - -2. **대상 파일 경로**: `docs/작업일지/.md` - -3. **내용 정리**: 사용자가 `args`로 전달한 내용을 작업일지 항목으로 정리한다. - - 단순 한 줄이면 그대로 한 항목으로. - - 여러 작업/생각이 섞여 있으면 자연스럽게 불릿(`-`)으로 나눈다. - - 사용자가 적은 의도/뉘앙스는 보존하고, 임의로 내용을 지어내지 않는다. - -4. **파일 기록**: - - 파일이 **없으면** 아래 템플릿으로 새로 만든다. - - 파일이 **있으면** 기존 내용을 Read한 뒤, 맨 아래에 새 항목을 이어 붙인다(append). 기존 내용은 절대 지우지 않는다. - - 같은 날 여러 번 호출되면 시각(`HH:MM`) 소제목을 붙여 구분한다. - -5. 기록 후, 어떤 파일에 무엇을 추가했는지 한 줄로 사용자에게 알린다. - -> **규약 바인딩.** **덮어쓰기가 되는 상황이면 먼저 승인받는다** (`rules.md` #2) — 정상 경로는 append라 -> 승인이 필요 없지만, 기존 파일을 재작성하거나 항목을 지우게 되면 무엇이 사라지는지 먼저 보고한다. -> 파일은 **UTF-8**로 쓴다 — 한글이 깨지면 안 된다 (`rules.md` #3). -> 작업일지 1건이 200줄을 넘으면 분할하고 상대경로로 링크한다 (`rules.md` #4). -> 사용자가 말하지 않은 내용을 채우지 않는다 (#9). 사용자 발언을 옮긴 것과 **네가 해석한 것을 섞지 말고**, -> 해석은 문장 앞에 `[추론]`을 붙인다 (#15·#16) — 작업일지는 나중에 사실 기록으로 인용된다. - -## 새 파일 템플릿 - -```markdown -# 작업일지 — yyyy-mm-dd - -## HH:MM -- (항목) -``` - -## 주의 - -- `args`가 비어 있으면 무엇을 기록할지 사용자에게 한 줄로 물어본다. -- 날짜/파일명 형식은 반드시 `yyyy_mm_dd`를 지킨다. -- 작업일지는 사용자의 기록이므로, 내용을 요약·각색하지 말고 사용자의 표현을 최대한 살린다. diff --git a/.claude/skills/optimize-ptop-build/SKILL.md b/.claude/skills/optimize-ptop-build/SKILL.md deleted file mode 100644 index 51850d8..0000000 --- a/.claude/skills/optimize-ptop-build/SKILL.md +++ /dev/null @@ -1,183 +0,0 @@ ---- -name: optimize-ptop-build -description: ILSOS_PrismaticRD_PTOP의 빌드 최적화 및 CI/CD 자동화. 멀티 구성 빌드(Debug/Release — Simulation·UserDefineUnit은 sln에서 Release로 매핑되어 별도 구성이 아니다) 분석, 의존성 최적화, 빌드 시간 단축, CI/CD 파이프라인 설계. "빌드 최적화", "PTOP 빌드 성능", "CI/CD 자동화 설계", "배포 파이프라인" 요청 시 사용. 구분 — 계층 구조는 `analyze-ptop-architecture`, 시퀀스 내부 로직은 `analyze-ptop-implementation`, 셋을 함께 보려는 종합 요청은 `orchestrate-ptop-harness`. 이 스킬은 분석·제안 전용이며 프로젝트 파일을 수정하지 않는다. 맨손 "업데이트"·"다시 실행"만으로는 이 스킬을 고르지 않는다 — 대상을 먼저 확인한다. ---- - -# Optimize PTOP Build Skill - -## 목표 - -ILSOS_PrismaticRD_PTOP의 **빌드 성능 및 자동화**를 최적화한다. - -## 분석 영역 - -### 1단계: 현재 빌드 상태 분석 - -**수집 대상:** -- 솔루션 내 프로젝트 목록 (ILSOS_All.sln) -- PTOP이 참조하는 프로젝트 -- 각 프로젝트의 빌드 시간 측정 - -**측정 방법:** - -`msbuild`는 **PATH에 없을 수 있다.** 먼저 탐색하고, 못 찾으면 측정을 포기하되 그 사실을 명시한다. - -```bash -# 1) PATH 확인 -command -v msbuild MSBuild.exe - -# 2) 없으면 vswhere로 탐색 (VS 2022 설치 시) -"/c/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe" \ - -latest -products '*' -find 'MSBuild/**/Bin/MSBuild.exe' - -# 3) 찾았으면 구성별 측정 (time으로 소요시간 확보) -time "" ILSOS_All.sln -p:Configuration=Release -p:Platform=x64 -``` - -> **셋 다 실패하면** 2개 구성의 시간 칸을 전부 `미측정`으로 확정하고, -> 보고서 "미측정·미검증"에 "MSBuild 미탐색 — 빌드 시간 측정 불가"를 사유와 함께 남긴다. -> 추정치를 채우지 않는다. 이 하네스는 빌드를 **실행만** 하고 프로젝트 파일을 고치지 않는다. - -**수집 항목:** (§3단계 참조 — PTOP의 실질 구성은 2개다) -| 구성 | 총 소요시간 | 병목 프로젝트 (상위 3) | 캐시 효율 | -|------|-----------|------------------|---------| -| Debug\|x64 | ? | ? | ? | -| Release\|x64 | ? | ? | ? | - -> `Simulation|x64`·`UserDefineUnit|x64`는 `ILSOS_All.sln:413-416`에서 PTOP이 `Release|x64`로 -> 매핑되어 **바이너리가 동일**하다. 별도 측정 대상이 아니므로 표에 행을 만들지 않는다. - -### 2단계: 의존성 분석 - -**PTOP의 최소 필수 의존성 파악:** - -의존성 트리를 **소스에서 직접 만든다.** 미리 적힌 필수/선택 판정을 그대로 옮기지 않는다 — -잘못된 판정을 따라 참조를 지우면 빌드가 깨진다. - -1. `Machines/ILSOS_PrismaticRD_PTOP/*.csproj`의 `` / `` 전수 수집 -2. 각 참조에 대해 **심볼이 실제로 쓰이는지 검색** (`using` 문만으로 판단하지 말 것 — 죽은 using이 있다) -3. 판정 근거를 기록: `필수 — <어느 코드가 쓰는가 파일:라인>` / `미사용 후보 — <검색 결과>` - -| 참조 | 종류 | 사용 근거(파일:라인) | 판정 | 제거 시 위험 | -|---|---|---|---|---| -| | ProjectReference / NuGet | | 필수 / 미사용 후보 / 불명확 | | - -**분석 시 주의:** -- 조건부 컴파일 심볼로만 쓰이는 참조가 있는지 확인한다. 단 **이 프로젝트의 `DefineConstants`는 - `DEBUG;TRACE` / `TRACE`뿐이고 `#if SIMULATION` 류는 0건**이므로(csproj 확인), 새 심볼을 가정하지 말 것. -- 리플렉션·DI 등록으로만 쓰이면 정적 검색에 안 잡힌다. `EquipmentSetup.cs`의 디바이스 등록부를 반드시 확인한다. - -**산출물:** `_workspace/04a_dependency_analysis.csv` - -### 3단계: 빌드 구성별 최적화 - -#### Debug|x64 최적화 -- 기호 생성 필요 (유지) -- 최적화 비활성화 (유지) -- 증분 빌드 활용 - -#### Release|x64 최적화 -`.csproj`는 **legacy 형식 + .NET Framework 4.8.1**이다. `PublishTrimmed`·`TieredCompilation`· -`DebugType=embedded` 같은 SDK 스타일(.NET Core/5+) 속성은 **동작하지 않는다.** 제안 전에 -해당 속성이 이 프로젝트 형식에서 유효한지 먼저 확인하라. - -#### Simulation|x64 / UserDefineUnit|x64 — 별도 컴파일 구성이 아니다 -`ILSOS_All.sln:413-416`에서 PTOP(`{8BB07B4C-…}`)의 `Simulation|x64`·`UserDefineUnit|x64`가 -`Release|x64`로 매핑된다. 즉 PTOP은 **Release와 동일한 바이너리**이며 출력도 `x64-Release/`다. -**다만 솔루션의 다른 프로젝트 상당수는 `Simulation|x64 → Debug|x64`이므로** -최소 빌드 집합을 논할 때 프로젝트별 매핑을 각각 확인해야 한다. - -시뮬레이션은 조건부 컴파일이 아니라 **런타임 플래그**로 갈린다 — -`Device/PLC/PLCContoller.Config.cs`의 `isSimul` 계열. `Machines/` 전체에 `#if SIMULATION`은 0건이고 -`DefineConstants`는 `DEBUG;TRACE` / `TRACE`뿐이다(csproj 확인). - -> 이 사실을 모르고 "Simulation 구성만 따로 최적화"를 제안하면 존재하지 않는 빌드를 대상으로 -> 삼게 된다. 구성별 차이를 논하기 전에 sln의 `ActiveCfg` 매핑을 먼저 읽어라. - -### 4단계: CI/CD 파이프라인 설계 - -**목표:** -- 자동 빌드 (commit, PR) -- 자동 테스트 — **Simulation은 별도 구성이 아니므로**(§3단계) 테스트 잡을 Simulation 구성으로 나누지 않는다. - 시뮬 동작은 런타임 `isSimul` 플래그로 켠다. -- 자동 배포 (수동 승인) - -**추천 플랫폼:** -- GitHub Actions (GitHub 저장소 사용 중 가정) -- Azure Pipelines (Microsoft 클라우드) -- Jenkins (온프레미스) - -**파이프라인 구조:** [references/cicd-pipeline-template.yml](references/cicd-pipeline-template.yml) -를 시작점으로 삼아 `_workspace/05_cicd_pipeline.yml`에 프로젝트 맞춤 버전을 쓴다. - -> 템플릿은 **미검증 초안**이다. 실제로 러너에서 돌려본 적이 없으므로, 검증 없이 -> "CI/CD 설계 완료"라고 보고하지 않는다. 검증 여부를 보고서에 명시한다. - -### 5단계: 배포 패키징 - -**산출물:** -- 실행 가능 파일 (Aurora.exe) -- 필수 DLL (AuroraDevices, WeldingComponents, etc.) -- 설정 파일 (app.config) -- 리소스 파일 (이미지, 데이터) -- 배포 설명서 - -**패키징 형식:** -- ZIP 아카이브 (간단) -- NSIS 설치 프로그램 (사용자 친화적) -- Chocolatey 패키지 (자동 업데이트) - -## 통합 산출물 - -### 최종 보고서: `_workspace/06_ptop_build_optimization.md` -(보조 산출물: `_workspace/04_build_analysis.md`, `_workspace/05_cicd_pipeline.yml`) - -보고서 골격은 [references/report-template.md](references/report-template.md) 참조. - -> **빌드 시간·크기·개선율을 지어내지 않는다.** 실제로 측정했을 때만 수치를 적고 측정 명령어를 -> 병기한다. 측정하지 않았으면 `미측정`이라고 쓴다. -> **"이 의존은 제거 가능해 보인다" 같은 미검증 판단에는 `[추론]`을 붙인다** (`rules.md` #15·#16). -> 심볼 참조를 실제로 검색해 확인한 뒤에만 표기를 떼고 근거를 병기한다. -> `미측정`(측정 못 함)과 축이 다르니 대체하지 말고 필요하면 병기한다. - -## 입력 조건 -> **단독 호출 시**: 생성할 `_workspace/` 파일 목록을 사용자에게 제시하고 승인받은 뒤 시작한다 -> (`rules.md` #2). 오케스트레이터(`orchestrate-ptop-harness`)를 통해 호출된 경우는 이미 승인을 받았으므로 생략한다. - - -사용자 요청 시: -- "PTOP 빌드 최적화" -- "빌드 시간 단축" -- "CI/CD 파이프라인 설계" -- "배포 자동화" -- "Release 빌드 성능" - -## 출력 결과 - -- 빌드 성능 분석 보고서 -- 의존성 맵핑 CSV -- CI/CD 파이프라인 (YAML/JSON) -- 빌드 최적화 설정 (PropertyGroup) -- 배포 패키징 스크립트 -- 최종 보고서 - -## 주의사항 - -1. **.NET Framework 4.8.1 호환성** — 최신 .NET 기능 사용 불가 -2. **Visual Studio 2022 기준** — MSBuild 경로 확인 -3. **Windows 플랫폼 전용** — x64 아키텍처 명시 -4. **빌드 머신 사양** — CI 환경의 OS/RAM 확인 -5. **라이선스 확인** — NuGet 패키지, 외부 도구의 라이선스 -6. **주석·프로퍼티명을 맹신하지 않는다** (`rules.md` #1) — 구성 이름(`Simulation`·`UserDefineUnit`)이 - 별도 컴파일을 뜻하지 않는 것이 그 예다. 판단 근거는 `.sln`·`.csproj` 실제 매핑이다. - -> **단독 기동으로 `04`~`06`을 갱신했으면 stale 표기 의무는 네게 있다.** "빌드 분석만 다시"는 -> `docs/harness-ptop.md` 가 후속 트리거로 열거한 발화라 이 스킬로 직접 들어올 수 있고, -> 그때는 오케스트레이터가 표기해 주지 않는다. 갱신한 파일 첫 줄에 `이번 실행에서 갱신됨(YYYY-MM-DD)`, -> 재사용한 기존 산출물 첫 줄에 `이전 실행 결과 재사용 — 정합성 미확인(YYYY-MM-DD)` 을 남긴다 -> (문구 3종 → `orchestrate-ptop-harness/references/data-protocol.md`). - -> 이 스킬은 10분을 넘긴다 — **단계 전환마다 지금 어느 단계인지 한 줄로 보고한다**(`rules.md` #10). -> -> 단독 호출로 마무리할 때: 보고는 `rules.md` #11~13 출력 형식(수정 줄=초록 화살표, 단어=주황, 미변경=기본색)을 -> 따르고, 끝에 관련 `.md`를 갱신할 부분이 있는지 묻는다(`rules.md` #6). diff --git a/.claude/skills/optimize-ptop-build/references/cicd-pipeline-template.yml b/.claude/skills/optimize-ptop-build/references/cicd-pipeline-template.yml deleted file mode 100644 index 231acb8..0000000 --- a/.claude/skills/optimize-ptop-build/references/cicd-pipeline-template.yml +++ /dev/null @@ -1,47 +0,0 @@ -# .github/workflows/ptop-build.yml -name: PTOP Build & Deploy - -on: - push: - branches: [main, develop] - paths: ['Machines/ILSOS_PrismaticRD_PTOP/**'] - pull_request: - branches: [main] - -jobs: - build: - runs-on: windows-latest - strategy: - matrix: - config: [Debug, Release] # Simulation/UserDefineUnit은 sln에서 Release로 매핑되므로 중복 - steps: - - uses: actions/checkout@v4 - - name: Setup .NET Framework - uses: microsoft/setup-msbuild@v2 - - name: Setup NuGet - uses: nuget/setup-nuget@v2 - - name: Restore NuGet - run: nuget restore ILSOS_All.sln - - name: Build (${{ matrix.config }}) - run: msbuild ILSOS_All.sln /p:Configuration=${{ matrix.config }} /p:Platform=x64 - - name: Upload Artifacts - uses: actions/upload-artifact@v4 - with: - name: ptop-${{ matrix.config }} - path: Machines/_out_prismatic_rd_ptop/x64-${{ matrix.config }}/ - # 주의: Simulation/UserDefineUnit을 matrix에 넣으면 출력은 x64-Release/ 이므로 경로가 어긋난다 - - deploy: - needs: build - runs-on: windows-latest - if: github.ref == 'refs/heads/main' - environment: production # 수동 승인 필수 - steps: - - name: Download Release Artifact - uses: actions/download-artifact@v4 - with: - name: ptop-Release - - name: Create Release Package - run: echo 'TODO 패키징 스크립트' - - name: Deploy to Server - run: echo 'TODO 배포 스크립트' diff --git a/.claude/skills/optimize-ptop-build/references/report-template.md b/.claude/skills/optimize-ptop-build/references/report-template.md deleted file mode 100644 index 7be64ae..0000000 --- a/.claude/skills/optimize-ptop-build/references/report-template.md +++ /dev/null @@ -1,57 +0,0 @@ -# 보고서 템플릿 — `_workspace/06_ptop_build_optimization.md` - -> 이 골격을 채워 통합 보고서를 만든다. -> -> **빌드 시간·크기·개선율을 지어내지 않는다.** 실제로 빌드를 돌려 측정했을 때만 수치를 적고, -> 측정 방법(명령어)을 함께 남긴다. 측정하지 않았으면 `미측정`이라고 쓴다. -> 그럴듯한 숫자가 보고서에 남으면 이후 최적화 우선순위 판단이 통째로 오염된다. - -```markdown -# PTOP 빌드 최적화 보고서 - -## 1. 현재 빌드 성능 - -| 구성 | 시간 | 측정 방법 | 병목 | 개선 가능성 | -|------|------|---|------|----------| -| Debug\|x64 | <측정값 또는 미측정> | <명령어> | | | -| Release\|x64 | | | | | - -> `Simulation`·`UserDefineUnit`은 sln에서 `Release|x64` 매핑 — 별도 행을 만들지 않는다. - -> 한 건도 측정하지 못했으면 표 전체를 `미측정`으로 두고, 그 사실을 §6에 명시한다. - -## 2. 의존성 최적화 - -### 필수 의존성 -| 프로젝트 | 왜 필수인가 | 근거(파일:라인) | -|---|---|---| - -### 제거 가능 후보 -| 프로젝트 | 왜 불필요해 보이는가 | 근거 | 제거 시 위험 | -|---|---|---|---| - -> "참조되지 않는 것 같다"는 근거가 아니다. 실제로 심볼 참조를 검색해 확인한 결과만 적는다. - -## 3. 빌드 구성별 최적화 전략 - -### Debug / Release -- 현황: <근거와 함께> -- 개선안: <구체적 설정 변경> -- 예상 효과: <측정 기반이면 수치, 아니면 "미측정 — 적용 후 재측정 필요"> - -## 4. CI/CD 파이프라인 - -<`_workspace/05_cicd_pipeline.yml` 참조. 여기엔 설계 의도와 트리거 조건만 요약> - -## 5. 배포 패키징 - -<포함 파일 목록 · 패키징 절차. 제안 단계이며 실제 스크립트 실행은 하지 않는다> - -## 6. 미측정·미검증 항목 - -| 항목 | 왜 확인 못 했는가 | 무엇을 하면 확정되는가 | -|---|---|---| -``` - -> **이 스킬은 분석·제안 전용이다.** `.csproj`·`.sln`·소스를 수정하지 않는다. -> 변경안은 diff 제안으로만 제시하고, 적용 여부는 사용자가 결정한다. diff --git a/.claude/skills/orchestrate-ptop-harness/SKILL.md b/.claude/skills/orchestrate-ptop-harness/SKILL.md deleted file mode 100644 index ae3c022..0000000 --- a/.claude/skills/orchestrate-ptop-harness/SKILL.md +++ /dev/null @@ -1,200 +0,0 @@ ---- -name: orchestrate-ptop-harness -description: >- - ILSOS_PrismaticRD_PTOP 분석 팀의 오케스트레이터. 3명(ptop-lead, ptop-developer, - build-devops-engineer)을 기동해 3계층 아키텍처·구현 상세·빌드 최적화를 분석하고 - (lead·build는 병렬, developer는 lead 완료 후 순차) - 통합 보고서를 만든다. "PTOP 프로젝트 종합 분석", "PTOP 전체 점검", "PTOP 하네스 시작", - "PTOP 팀 조율", "PTOP 구조 파악", 그리고 **PTOP 분석에 대한** 후속 표현("PTOP 재분석", - "PTOP 다시 점검", "아키텍처만 다시", "빌드 분석만 다시", "이전 분석 결과 기반으로") 시 이 스킬을 쓴다. - 구분 — 단일 영역만 필요하면 개별 스킬(analyze-ptop-architecture / analyze-ptop-implementation / - optimize-ptop-build)을, **산출물 문서**를 만들거나 갱신하는 요청("산출물 업데이트/재생산")은 - ptop-deliverables·ubisam-deliverable-rebuild·ubisam-deliverables를, 코드를 실제로 고치는 작업은 - code_Agent를 쓴다. 맨손 "업데이트"·"다시 실행"만으로는 이 스킬을 고르지 않는다 — 대상을 먼저 확인한다. ---- - -# Orchestrate PTOP Harness - -`ILSOS_PrismaticRD_PTOP`의 **아키텍처 · 구현 · 빌드**를 세 전문가가 병렬 분석해 통합 보고서를 만든다. -이 하네스는 **읽기·분석 전용**이다. 소스 코드를 수정하지 않는다. - -## 실행 모드 - -**서브 에이전트 병렬 + 의존 순차.** 이 환경에는 `TeamCreate`/`TeamDelete` 도구가 **없으므로** -아래 도구로 팀을 구성한다. - -| 목적 | 도구 | -|---|---| -| 팀원 기동 | `Agent` — `subagent_type`에 에이전트 이름, `model: "opus"`, 병렬 구간은 `run_in_background: true` | -| 팀원 간 소통 | `SendMessage` — `to`에 에이전트 **이름**, `summary`(5~10단어)는 **필수**, `message`는 본문 | -| 진행 공유 | `_workspace/_progress.md` (진실원) + `TaskCreate`/`TaskUpdate`(가용 시 보조) | -| 산출물 전달 | 파일 — `_workspace/` | - -``` -[오케스트레이터] - Phase 1 컨텍스트 확인 - Phase 2 ptop-lead + build-devops-engineer 병렬 기동 - Phase 3 lead 산출 완료 → ptop-developer 기동 (아키텍처 결과 의존) - Phase 4 결과 수집 · 상충 조정 - Phase 5 통합 보고서 작성 -``` - -## 팀 구성 - -| 에이전트 | 담당 | 사용 스킬 | 산출 (에이전트 정의와 일치) | -|---|---|---|---| -| `ptop-lead` | 3계층 아키텍처·디바이스 스택·시퀀스 의존성 | `analyze-ptop-architecture` | `01_ptop_architecture.md` | -| `ptop-developer` | 시퀀스 상태머신·타이밍·Rx 체인·에러 처리 | `analyze-ptop-implementation` | `02_ptop_implementation.md`, `03_device_integration.md` | -| `build-devops-engineer` | 멀티 구성 빌드·의존성·CI/CD | `optimize-ptop-build` | `04_build_analysis.md`, `05_cicd_pipeline.yml`, `06_ptop_build_optimization.md` | - -모두 `_workspace/` 하위이며 `model: "opus"`로 기동한다. 파일명은 각 에이전트 정의의 -`입력/출력 프로토콜` 절이 진실원이며, 바꿀 때는 **에이전트 정의·담당 스킬·이 표를 함께** 고친다. - -> **진행 원장은 `_workspace/_progress.md` 파일이다.** `TaskCreate`/`TaskUpdate`는 메인 루프에서는 -> 쓸 수 있지만 **서브에이전트 컨텍스트에는 없을 수 있어**, 도구 가용 여부와 무관하게 동작하도록 -> 파일을 진실원으로 둔다. 표 형식 → [references/data-protocol.md](references/data-protocol.md) - -## Phase 1: 컨텍스트 확인 - -0. **대상 확인.** 발화에 **PTOP 분석 대상이 명시돼 있지 않으면** 어떤 Phase도 시작하지 말고 되묻는다. - 맨손 "다시 실행"·"업데이트"·"보완"처럼 대상 없는 발화와, "산출물" 같은 타 하네스 어휘가 섞인 - 발화가 **각각 독립적으로** 걸린다(둘 다일 필요 없다). 그냥 진행하면 기존 산출물이 이동될 수 있다. -1. `_workspace/`(**저장소 루트 기준.** Ubisam 하네스의 `docs/[Ubisam산출물]/_workspace/`와 다른 곳)의 - **산출물 `01`~`06` 존재 여부**와 **요청 범위** 두 축으로 판별한다(폴더만 보면 오판정한다): - 없음→**`초기`** / 일부+전체요청→**`이어서`** / 특정영역요청→**`부분`** / "처음부터 다시"→**`전면`** - - 네 모드의 이름은 **`초기` / `이어서` / `부분` / `전면`** 이며, 이 문자열 그대로 전달한다(§Phase 2). - **판별 기준·기동 범위·생략의 파급 → [references/mode-rules.md](references/mode-rules.md)** -2. **에이전트 가용성 확인.** `ptop-lead` / `ptop-developer` / `build-devops-engineer`가 - `Agent` 도구의 subagent_type 목록에 있는지 먼저 본다. 없으면 **어떤 Phase도 시작하지 말고** - "프로젝트 에이전트 미등록 — 세션 재시작 필요"를 사용자에게 보고하고 중단한다. - `.claude/agents/`에 파일을 새로 추가·이동한 직후에는 **세션이 재시작돼야 등록된다.** - 파일이 있다는 것과 호출 가능하다는 것은 다르다. -3. `docs/architecture.md`로 프로젝트 사실을 확보한다. -4. **승인 게이트.** 아래 **넷을 한 번에** 제시하고 승인받는다 (`rules.md` #2) — - ① **이동·삭제분**(전면 재실행이면 `_workspace/` → `_workspace_prev/` 이동. 1번에서 스스로 - "되돌리기 어려운 이동"이라 경고한 그 동작이다) ② 덮어쓰기분 ③ 생성분 - ④ **작업공간 관리 파일**(`_workspace/` 폴더 생성, `_progress.md`, 단계별 중간 로그, - **재사용 산출물의 stale 첫 줄 편집** — §후속 작업의 표기 의무가 기존 파일을 고치므로 승인 대상이다). - ④를 빼면 에이전트가 자기 작업 로그조차 승인 범위 밖이 되어 쓸 수 없다. - 모드 판별을 승인보다 먼저 하는 이유는, 그러지 않으면 승인 목록이 실제 변경 범위와 어긋나기 때문이다. - 생성분 목록은 — - 통합 산출 `01~06` + `00_PTOP_HARNESS_SUMMARY.md` + **부산출물** `01a~01e`(analyze-ptop-architecture)· - `04a_dependency_analysis.csv`(optimize-ptop-build) — - 승인을 받은 뒤 Phase 2로 간다 (`rules.md` #2 — 수정은 무조건 승인받기). -5. `_workspace/_progress.md`를 만들고 **에이전트 3인 전원의 행**을 초기화한다. 상태 enum은 - **`진행중`/`완료`/`실패`/`생략` 4종**(정의 → `references/data-protocol.md` §진행 원장). - **이번 실행에서 기동하지 않는 에이전트는 모드와 무관하게 `생략 — 이전 산출물 재사용`** 으로 - 적는다 — `이어서`의 건너뜀도, `부분`에서 지목되지 않은 것도 같다(§Phase 2·3·4가 이 값을 읽는다). - `TaskCreate`가 가용하면 함께 등록하고 02는 01에 `addBlockedBy`를 건다 — 미지원이면 - **Phase 3의 파일 존재 판정으로 대체**한다(의존성 표현이 없어도 완료 판정은 관측 가능하다). - -## Phase 2: 병렬 분석 (lead + build) - -`ptop-lead`와 `build-devops-engineer`는 서로 의존이 없다 → `run_in_background: true`로 **동시** 기동. - -먼저 `_workspace/`가 없으면 만든다. 각 에이전트에 전달할 것: -- 담당 스킬을 **저장소 루트 기준 절대경로**로 전달한다 — `/.claude/skills/<스킬명>/SKILL.md`. - 이름만 주면 서브에이전트가 경로를 스스로 찾아야 한다. -- **산출 파일 경로**와 **진행 원장 `_workspace/_progress.md`** 를 모두 **저장소 루트 기준 절대경로**로 전달 — - 서브에이전트 셸 cwd는 호출마다 초기화되므로 상대경로는 엉뚱한 곳에 떨어진다. 산출물이 유실되면 - Phase 3 완료 판정이 "파일 없음 → 실패"로 오판하고, 원장이 흩어지면 "최대 2회" 상한이 무력화된다. -- "모든 주장에 `파일:라인` 근거를 붙일 것" -- **실행 모드(초기 / 이어서 / 부분 / 전면 — 4종).** 팀원은 이 값을 **기존 산출물을 재사용할지** - 판단에만 쓴다. **`_workspace_prev/` 이동은 오케스트레이터 전담이며 Phase 1에서 이미 끝났다** — - 팀원이 한 번 더 옮기면 병렬로 쓰이던 산출물이 딸려간다. - -> **기동 축소 기준은 모드마다 다르다**(원장에 `생략` 을 적는 것은 §Phase 1-5 대로 공통): -> **`이어서`**=담당 산출물이 이미 있으면 / **`부분`**=지목되지 않았으면 / **`초기`·`전면`**=전원 기동. -> ⚠ `부분` 에서 **산출물 유무는 기준이 아니다** — 있다는 이유로 생략하면 재기동 대상이 곧 생략 -> 대상이 되어 **아무도 기동되지 않는다**. -> -> **생략한 에이전트는 완료 알림을 보내지 않으므로** `_progress.md`에 `생략 — 이전 산출물 재사용` 으로 -> 기록하고 §Phase 3·4의 판정을 바꾼다 → [references/mode-rules.md](references/mode-rules.md) - -## Phase 3: 의존 분석 (developer) - -`ptop-lead`의 `01_ptop_architecture.md` 완성 후 `ptop-developer`를 기동한다. -구현 분석이 아키텍처가 정의한 계층 경계를 기준으로 이뤄져야 하기 때문이다. -**단 developer 자신이 생략 대상이면 기동하지 않는다 — 아래 "developer 자신을 생략하는 경우"를 먼저 판정한다.** - -**완료 판정(관측 가능해야 한다):** 먼저 lead의 **백그라운드 완료 알림을 기다린다.** -알림이 온 뒤 `_workspace/01_ptop_architecture.md`가 존재하고 "불명확 — 확인 필요" 절까지 -채워져 있으면 완료로 본다. 알림은 왔는데 파일이 없으면 1회만 재확인하고, 그래도 없으면 실패로 처리한다. -**알림 전에 파일 유무만으로 미완을 단정하지 않는다.** - -> **예외 — lead를 생략한 경우**(`§Phase 2` 축소 규칙, `_progress.md`에 `생략` 으로 기록됨). -> 생략된 에이전트는 **알림을 보내지 않는다.** 이때는 알림을 기다리지 말고 `01`의 **파일 존재만으로 -> 완료 판정**하고 곧바로 developer를 기동한다. 이 예외가 없으면 오지 않을 알림을 무기한 대기한다. - -> **developer 자신을 생략하는 경우.** `이어서` 이고 `02`·`03`이 **둘 다 이미 있으면** developer를 -> 기동하지 않는다. `부분` 이면 developer가 **지목됐을 때만** 기동한다("아키텍처만 다시" → 기동 안 함). -> 기동하지 않기로 했으면 `_progress.md`의 developer 행을 `생략 — 이전 산출물 재사용` 으로 적고 -> Phase 4로 넘어간다. 이 판단을 하지 않으면 재사용 대상인 `02`·`03`을 덮어쓴다 -> (`mode-rules.md` §기동 범위가 이 문장을 수신처로 지목한다). - -developer에게도 **Phase 2와 동일한 항목 일체**를 전달한다(담당 스킬 = `analyze-ptop-implementation`, 산출 = `02`·`03`). -**`run_in_background: true` 로 기동한다** — 순차 구간이라 불필요해 보이지만 `SendMessage`의 -`to: "main"` 회신은 **백그라운드 전용**이라, 전경으로 띄우면 Phase 4 회신 경로가 막힌다. - -**폴백:** lead가 **2회 실패로 확정되면**(지연은 실패가 아니다 — `references/error-handling.md`) -developer를 **소스 직접 참조 모드**로 기동하고 "아키텍처 선행 없이 수행됨"을 보고서에 명시한다. -기동은 **오케스트레이터만** 한다 — `ptop-lead`는 범위 전달만 하고 팀원을 띄우지 않는다. - -## Phase 4: 결과 수집 · 상충 조정 - -**이번 실행에서 기동한** 에이전트의 완료 알림을 받은 뒤 산출 파일 완성을 확인한다 -(알림 전 파일 유무로 실패를 단정하지 않는다). 그 다음 `SendMessage`로 핵심 발견 3건씩을 요청한다. - -**원장 상태에 따라 3분기다** — `완료`=보낸다 / `실패`=`미검증` / **`생략`=산출물을 직접 읽어 답을 채운다** -(`미검증`이 아니다). 둘을 묶으면 `부분`·`이어서` 실행이 매번 교차 질문을 통째로 잃는다. -**대상 판별·교차 확인 질문 2건 → [references/collection-rules.md](references/collection-rules.md)** - -상충하는 답이 나오면 어느 쪽도 지우지 않고 양쪽을 **근거(파일:라인)와 함께 병기**한다. - -## Phase 5: 통합 보고서 - -`_workspace/00_PTOP_HARNESS_SUMMARY.md`를 작성한다. -**필수 섹션 7종·표기 규약·중단 시 선작성 규칙 → [references/summary-template.md](references/summary-template.md)** -(수치 추정 금지, `[추론]` 표기 `rules.md` #15·#16, `미검증·불명확` 절이 모든 누락의 종착지). - -**보고 규약** — Phase 전환마다 진행 1줄 보고(`rules.md` #10), 출력 형식은 #11~13(수정 줄=초록 -화살표, 단어=주황, 미변경=기본색), 끝에 `docs/harness-ptop.md` 갱신 여부를 묻는다(#6). - -## 데이터 전달 · 에러 핸들링 - -전달 = 파일(`_workspace/`) + `SendMessage`(이름) + `_progress.md`(진행 원장). -상세 → [data-protocol.md](references/data-protocol.md) · [error-handling.md](references/error-handling.md) - -**에러 핵심 3가지:** -- 실패 = ①에러 종료 ②산출 파일 미생성 ③빈 파일·헤더만. **지연은 실패가 아니다.** -- 재시도는 같은 `Agent` 재호출이며 `SendMessage` 독촉이 아니다. 횟수는 `_progress.md`에 `시도 N/2` 기록. -- 1회 재시도 후 재실패하면 해당 영역 없이 진행하고 **누락을 `00_PTOP_HARNESS_SUMMARY.md`에 명시**한다. - -## 테스트 시나리오 - -정상 · 에러 · 부분 재실행 · 전원 실패 **4흐름** → [references/test-scenarios.md](references/test-scenarios.md) - -## 성공 기준 - -- [ ] 통합 산출 6건(01~06)이 존재하거나, 없으면 누락 사유가 보고서에 명시됨 - (부산출물 `01a~01e`, `04a_dependency_analysis.csv`는 각 스킬이 만들며 필수는 아님) -- [ ] 모든 발견에 `파일:라인` 근거가 붙어 있음 -- [ ] 측정하지 않은 수치가 보고서에 없음 -- [ ] 검증 전 서술이 전부 `[추론]`으로 표기됨 (`rules.md` #16) -- [ ] 교차 확인 질문 2건에 답이 기록됨 — 답할 에이전트가 **실패**했으면 `미검증`과 사유로, - **`생략`(미기동)** 이면 그 산출물을 읽어 `이전 실행 산출물에서 확인(YYYY-MM-DD)` 으로 대체 가능 -- [ ] 상충 사항이 양쪽 근거와 함께 병기됨 -- [ ] 권장사항이 P0/P1/P2로 분류됨 -- [ ] 부분 재실행이면 각 산출 파일과 보고서에 **stale 표기**가 있고, 연쇄 무효화 여부가 기록됨 -- [ ] 소스 코드가 수정되지 않음 (분석 전용) - -## 후속 작업 - -- "아키텍처만 다시" → `ptop-lead`만 재기동, 나머지는 기존 `_workspace/` 파일 재사용 -- **stale 표기 의무.** 각 산출 파일(`01`~`06`)의 **첫 줄**과 보고서 각 영역 절 머리 **양쪽에** - `이번 실행에서 갱신됨(YYYY-MM-DD)` / `이전 실행 결과 재사용(YYYY-MM-DD)` 를 적는다(§Phase 1-4 ④ 승인 대상). - `01`을 갱신하면 의존하는 `02`·`03`은 재사용이 아니라 **정합성 미확인** — 함께 재실행할지 묻고 - 거절하면 사유까지 표기한다. 날짜 규칙·문구 3종 → [data-protocol.md](references/data-protocol.md) -- 부분 재실행에서는 `_workspace_prev/`로 옮기지 않는다(전면 재실행일 때만). 갱신 대상 파일만 덮어쓴다. -- 주요 코드 변경 후 영향도 분석 필요 시 전면 재실행 (기존은 `_workspace_prev/`로 보존) diff --git a/.claude/skills/orchestrate-ptop-harness/references/collection-rules.md b/.claude/skills/orchestrate-ptop-harness/references/collection-rules.md deleted file mode 100644 index de24b7d..0000000 --- a/.claude/skills/orchestrate-ptop-harness/references/collection-rules.md +++ /dev/null @@ -1,39 +0,0 @@ -# Phase 4 결과 수집 — 대상 판별 규칙 - -`SKILL.md` §Phase 4 에서 분리한 상세. **누구에게 `SendMessage` 를 보내고 누구에게 안 보내는가**를 -정한다. 판별 근거는 `_workspace/_progress.md` 의 상태 열이다(enum 4종 → `data-protocol.md` §진행 원장). - -## 알림 대기 대상 - -**이번 실행에서 기동한** 백그라운드 에이전트의 완료 알림을 전부 받은 뒤 산출 파일 완성을 확인한다. -알림 전 파일 유무로 실패를 단정하지 않는다. - -**`생략` 으로 적힌 에이전트는 알림 대상이 아니다** — 기동하지 않았으므로 알림을 보내지 않는다. -기다리지 말고 파일 존재로 판정한다. - -## 상태별 처리 (3분기) - -| 원장 상태 | `SendMessage` | 교차 확인 질문 답 | -|---|---|---| -| **`완료`** (= 살아 있는) | 보낸다 — 핵심 발견 3건 요청 | 회신 내용으로 채운다 | -| **`실패`** | 보내지 않는다 | `미검증` + 사유 | -| **`생략`** | 보내지 않는다 | **산출물 파일을 직접 읽어** 채우고 `이전 실행 산출물에서 확인(YYYY-MM-DD)` | - -**`살아 있는` = 완료 알림을 정상 수신했고 산출 파일이 실패 판정 ①②③에 걸리지 않은 에이전트.** -이 정의가 없으면 전부 죽었다고 보고 교차 질문 2건을 통째로 `미검증` 처리하게 된다. - -> ⚠ **`실패` 와 `생략` 을 한 처리로 묶지 마라.** 묶으면 `부분`·`이어서` 실행이 **매번** 교차 질문 -> 2건을 `미검증` 으로 떨어뜨린다 — 산출물은 멀쩡히 있는데도 그렇다. -> `실패` 는 답할 근거가 없는 것이고, `생략` 은 답할 근거가 **파일에 있는** 것이다. - -## 교차 확인 질문 (반드시 물을 것) - -- 아키텍처가 정의한 3계층 경계가 구현에서 실제로 지켜지는가? 위반 지점은 어디인가? -- 런타임 시뮬 플래그(`isSimul`) 경로가 디바이스 시뮬 분기와 일관되는가? - (`Simulation|x64`는 별도 빌드가 아니므로 "구성"으로 묻지 않는다 — `optimize-ptop-build` §3단계 참조) - -상충하는 답이 나오면 어느 쪽도 지우지 않고 양쪽을 **근거(파일:라인)와 함께 병기**한다. - -> 위 표의 분기를 늘리거나 상태 enum을 바꾸면 `data-protocol.md` §진행 원장(정의부)과 -> `SKILL.md` §성공 기준의 교차 질문 항목을 **같은 편집에서** 고친다 -> (`docs/harness-ptop.md` §소비처 확인 의무 ①~④). diff --git a/.claude/skills/orchestrate-ptop-harness/references/data-protocol.md b/.claude/skills/orchestrate-ptop-harness/references/data-protocol.md deleted file mode 100644 index d8034e0..0000000 --- a/.claude/skills/orchestrate-ptop-harness/references/data-protocol.md +++ /dev/null @@ -1,45 +0,0 @@ -# 데이터 전달 프로토콜 — orchestrate-ptop-harness - -| 대상 | 방식 | -|---|---| -| 아키텍처 → 구현 의존 | 파일 (`_workspace/01_ptop_architecture.md`) | -| 실시간 질문·상충 | `SendMessage` (이름 지정) | -| 진행 추적 | `_workspace/_progress.md`(진실원) + `TaskCreate`/`TaskUpdate`(가용 시 보조, 02는 01에 blockedBy) | -| 최종 산출물 | `_workspace/00_PTOP_HARNESS_SUMMARY.md` | - -## 진행 원장 `_workspace/_progress.md` - -**진행 원장은 파일이다.** `TaskCreate`/`TaskUpdate`는 메인 루프에서는 쓸 수 있지만 -**서브에이전트 컨텍스트에는 없을 수 있다.** 도구 가용 여부와 무관하게 동작하도록, -진행·재시도 기록의 **진실원은 `_workspace/_progress.md`** 로 둔다: - -| 에이전트 | 상태 | 시도 | 갱신시각 | -|---|---|---|---| -| ptop-lead | 진행중 / 완료 / 실패 / **생략** | 1/2 | YYYY-MM-DD HH:MM | - -**상태 enum은 4종이다.** `진행중`·`완료`·`실패` 는 이번 실행에서 **기동한** 에이전트의 상태이고, -**`생략 — 이전 산출물 재사용`** 은 **이번 실행에서 기동하지 않은** 에이전트를 뜻한다 -(모드와 무관하다 — `이어서`에서 산출물이 이미 있어 건너뛴 경우든, `부분`에서 지목되지 않은 -경우든 똑같이 `생략` 으로 적는다). - -> **`생략` 을 적지 않으면 19R의 교착이 재발한다.** Phase 3·4는 이 값으로 -> "완료 알림을 기다릴 대상"과 "파일 존재로 판정할 대상"을 가른다. `진행중` 으로 적으면 -> 오지 않을 알림을 무기한 기다린다. 소비처 → `mode-rules.md` §생략의 파급. - -`TaskCreate`/`TaskUpdate`가 있으면 보조로 함께 쓰되, 없다고 해서 절차가 멈추지 않는다. - -## stale 표기 — 날짜 규칙과 연쇄 무효화 - -표기 위치는 **각 산출 파일(`01`~`06`)의 첫 줄**과 통합 보고서의 각 영역 절 머리, **양쪽 모두**다. -보고서에만 적으면 파일을 직접 여는 사람이 최신 여부를 알 수 없다. - -| 상황 | 첫 줄 문구 | -|---|---| -| 이번 실행에서 새로 씀 | `이번 실행에서 갱신됨(YYYY-MM-DD)` | -| 이전 판을 그대로 재사용 | `이전 실행 결과 재사용(YYYY-MM-DD)` | -| 선행 산출이 갱신돼 정합성 미확인 | `이전 실행 결과 재사용 — 01 갱신으로 정합성 미확인(YYYY-MM-DD)` | - -- 날짜는 **그 파일을 실제로 쓴 실행일**이다. 재사용할 때는 **그 파일에 이미 적힌 날짜를 그대로 옮긴다** — - 파일 mtime을 추정해 적지 않는다. -- **연쇄 무효화:** `01`을 갱신하면 그것에 의존해 만들어진 `02`·`03`은 단순 "재사용"이 아니라 - **정합성 미확인** 상태다. 함께 재실행할지 사용자에게 묻고, 거절하면 3행 문구로 표기한다. diff --git a/.claude/skills/orchestrate-ptop-harness/references/error-handling.md b/.claude/skills/orchestrate-ptop-harness/references/error-handling.md deleted file mode 100644 index a454561..0000000 --- a/.claude/skills/orchestrate-ptop-harness/references/error-handling.md +++ /dev/null @@ -1,15 +0,0 @@ -# 에러 핸들링 — orchestrate-ptop-harness - -| 상황 | 처리 | -|---|---| -| 에이전트 타입 미등록 | Phase 시작 전 중단 → "세션 재시작 필요" 보고 (Phase 1-2) | -| **재시도 카운트** | 재시도 횟수는 **`_workspace/_progress.md`의 `시도` 칸**에 기록한다(가용하면 `TaskUpdate`에도 병행). 기록이 없으면 0회로 간주 — 대화 맥락에만 두면 3회째로 새거나 1회에서 조기 포기한다 | -| **실패 판정 기준** | ① 에이전트가 에러로 종료 ② 지정 산출 파일이 생성되지 않음 ③ 산출 파일이 비었거나 헤더만 있음 — 셋 중 하나면 실패로 본다. **지연은 실패가 아니다.** 재시도는 같은 `Agent` 호출을 다시 하는 것이며 `SendMessage` 독촉이 아니다 | -| 반쯤 쓰인 산출 파일 | 지우지 않고 파일 상단에 `(부분 — 미완)`을 표기해 보존. 통합 보고서에서 해당 영역을 `부분`으로 표시 | -| 에이전트 실패 | 1회 재시도. 재실패 시 해당 영역 없이 진행하고 보고서에 **누락을 명시** | -| lead **지연** → developer 대기 | `run_in_background`로 띄운 에이전트는 **완료 알림이 올 때까지 기다린다.** 알림 없이 미완을 판단하지 않는다(기동 직후 확인하면 당연히 미완이라 폴백으로 오인된다). 알림이 온 뒤에도 산출 파일이 없으면 1회 재확인하고, 그래도 없으면 실패로 처리한다 | -| lead **2회 실패** (지연과 다름) | developer를 소스 직접 참조 모드로 기동(`ptop-developer.md` 재호출 지침). **부분 `01`이 남아 있으면 그것을 함께 전달하되 `(부분 — 미완)`임을 명시한다.** `01` 누락과 그 영향을 보고서에 적고, 아키텍처 관련 교차 질문은 `미검증` 처리 | -| 죽은 에이전트에 SendMessage | 보내지 않는다. 해당 교차 질문을 `미검증`으로 기록 | -| 코드 이해 불가 | 해당 지점을 "불명확 — 확인 필요"로 표기하고 진행. 추측으로 메우지 않는다 | -| 에이전트 간 상충 | 양쪽 견해를 근거와 함께 병기 | -| 근거 없는 주장 발견 | 해당 항목을 보고서에서 제외하거나 "근거 미확보"로 강등 | diff --git a/.claude/skills/orchestrate-ptop-harness/references/mode-rules.md b/.claude/skills/orchestrate-ptop-harness/references/mode-rules.md deleted file mode 100644 index 8912006..0000000 --- a/.claude/skills/orchestrate-ptop-harness/references/mode-rules.md +++ /dev/null @@ -1,72 +0,0 @@ -# 실행 모드 4종 — 판별 · 전달 · 기동 범위 - -`SKILL.md` §Phase 1·2 에서 분리한 상세 규약. 모드 이름은 **`초기` / `이어서` / `부분` / `전면`** 이며 -이 문자열 그대로 팀원에게 전달한다. - -## 판별 (Phase 1) - -`_workspace/`(**저장소 루트 기준**. Ubisam 하네스의 `docs/[Ubisam산출물]/_workspace/`와 다른 곳)의 -**분석 산출물 `01`~`06` 존재 여부**로 판별한다 — 폴더 존재만 보면 채점·로그 파일만 있어도 오판정한다. - -**두 축을 각각 본 뒤 교차한다** — ① 산출물 `01`~`06`이 있는가 ② 요청이 전체인가 특정 영역인가. -한 축만 보면 오판정한다. - -| ① 산출물 상태 | ② 요청 | 모드 | 동작 | -|---|---|---|---| -| 하나도 없음 | 전체 / 특정 영역 **무관** | **`초기`** | Phase 2부터 전원 기동. 폴더가 있어도, 특정 영역만 요청받았어도 만들 것이 없으므로 전원이다 | -| 일부만 있음 | 전체 | **`이어서`** | 있는 것 재사용, **없는 것만 생성**, 이동 없음 | -| 일부·전부 있음 | 특정 영역("아키텍처만 다시") | **`부분`** | **지목된 에이전트를 다시 돌린다.** 나머지는 재사용, 이동 없음 | -| 무관 | **"처음부터 다시" 명시** | **`전면`** | 기존을 `_workspace_prev/`로 이동. ②가 ①을 덮는 유일한 행 | - -> **①이 "하나도 없음"이면 ②를 보지 않고 `초기`다.** 산출물 0건인데 "아키텍처만 다시"를 받으면 -> `부분`처럼 보이지만, 재사용할 것이 없으므로 `초기`로 처리하고 사용자에게 그 사실을 알린다. -> 반대로 **`전면`은 ②가 우선**한다 — "처음부터 다시"는 산출물 상태와 무관한 명시적 지시다. -> -> 맨 "전체 분석"은 최초 실행과 같은 발화라 **이동 근거가 아니다** — 되돌리기 어려우니 확인 후 옮긴다. -> `_workspace_prev/` 이동은 **오케스트레이터만** 한다. 팀원은 모드를 "재사용할지" 판단에만 쓴다 -> (에이전트 정의 6종에 같은 금지문이 있다 — 한쪽만 고치지 말 것). -> -> **`생략` 으로 적었는데 해당 산출물 파일이 실제로 없으면** 그 에이전트는 생략 대상이 아니다. -> 원장을 `진행중` 으로 고치고 기동한다 — 파일 존재 판정(§생략의 파급 2)이 성립하지 않기 때문이다. - -## 기동 범위 (Phase 2) - -**기동 대상을 줄이는 기준은 모드마다 다르다**(아래 §모드별 기준 표). `이어서` 는 **담당 산출물이 -이미 있으면** 띄우지 않으며 **에이전트 3인 전원이 대상이다**: - -| 에이전트 | 담당 산출물 | 전부 있으면 | -|---|---|---| -| `ptop-lead` | `01` | 생략 | -| `build-devops-engineer` | `04`·`05`·`06` | 생략 | -| `ptop-developer` | `02`·`03` | 생략 — 판단 시점만 Phase 3다 (`SKILL.md` §Phase 3 "developer 자신을 생략하는 경우") | - -모드가 바꾸는 것이 이동 여부뿐이면 "있는 것 재사용, 없는 것만 생성"이라는 정의가 지켜지지 않는다. - -⚠ **`부분`은 기준이 다르다 — 산출물 유무가 아니라 "지목됐는가"다.** `부분`은 지목된 에이전트를 -**다시 돌리는** 모드라, 산출물이 있다는 이유로 생략하면 **재기동 대상이 곧 생략 대상이 되어 -아무도 기동되지 않는다.** `부분`에서는 지목된 에이전트를 반드시 띄우고, 지목되지 않은 에이전트만 -재사용한다(그쪽이 `생략` 이다). - -`초기`·`전면` 은 전원 기동이며 생략이 없다. - -| 모드 | 기동하지 않는 조건 | -|---|---| -| `초기` · `전면` | 없음 (전원 기동) | -| `이어서` | 담당 산출물이 **이미 있음** | -| `부분` | **지목되지 않음** (산출물 유무 무관) | - -## 생략의 파급 (Phase 3·4) - -**생략된 에이전트는 완료 알림을 보내지 않는다.** 알림을 기다리면 무기한 대기한다. - -> **`생략` 은 모드가 아니라 "이번 실행에서 기동하지 않음"을 뜻한다.** `이어서`에서 산출물이 -> 이미 있어 건너뛴 경우와 **`부분`에서 지목되지 않은 경우 둘 다** 여기에 해당한다. -> 상태 enum 정의부 → `data-protocol.md` §진행 원장. - -1. 기동하지 않는 에이전트를 `_progress.md`에 **`생략 — 이전 산출물 재사용`** 으로 먼저 기록한다. -2. Phase 3·4는 그 에이전트를 **알림 대기 없이 파일 존재만으로 완료 판정**한다. -3. 생략된 에이전트는 Phase 4의 "살아 있는" 대상이 **아니다** — 교차 확인 질문을 보내지 않는다. -4. 그 산출물에는 `SKILL.md` §후속 작업의 **재사용 stale 문구**를 남긴다. - -> 기동 대상을 늘리거나 줄이는 규칙을 고치면 **위 3개 소비처(Phase 2 기동 · Phase 3 완료 판정 · -> Phase 4 교차 질문)를 같은 편집에서 확인**한다 (`docs/harness-ptop.md` §소비처 확인 의무). diff --git a/.claude/skills/orchestrate-ptop-harness/references/summary-template.md b/.claude/skills/orchestrate-ptop-harness/references/summary-template.md deleted file mode 100644 index 598c84b..0000000 --- a/.claude/skills/orchestrate-ptop-harness/references/summary-template.md +++ /dev/null @@ -1,38 +0,0 @@ -# `00_PTOP_HARNESS_SUMMARY.md` 골격 - -오케스트레이터 Phase 5가 쓰는 통합 보고서의 필수 섹션이다. -`_workspace/00_PTOP_HARNESS_SUMMARY.md` 한 파일로 만든다. - -## 필수 섹션 - -| 섹션 | 내용 | -|---|---| -| Executive Summary | 3~5줄 | -| 영역별 발견 | 아키텍처(01) / 구현(02·03) / 빌드(04·05·06) — 각 3건 이상, 모두 `파일:라인` 근거 포함 | -| 상충 사항 | 에이전트 간 이견과 양쪽 근거 | -| 권장사항 | P0/P1/P2 · 항목 · 근거 · 예상 공수 | -| **산출물 stale** | 파일별 "이번 실행 갱신(YYYY-MM-DD)" / "이전 결과 재사용(YYYY-MM-DD)" + 연쇄 무효화 상태 | -| 미검증·불명확 | 확인하지 못한 항목과 사유 | -| 부록 | 산출 파일 목록 | - -> 섹션을 늘리거나 줄이면 `SKILL.md` §성공 기준의 대응 항목도 **같은 편집에서** 고친다 -> (`docs/harness-ptop.md` §소비처 확인 의무). - -## 표기 규약 - -**수치·상태를 추정으로 적지 않는다.** 빌드 시간·성능 수치는 실제 측정했을 때만 기재하고, -측정하지 않았으면 `미측정`이라고 쓴다. 그럴듯한 숫자가 보고서에 남으면 이후 판단을 오염시킨다. - -**검증 전 서술에는 `[추론]`을 붙인다** (`rules.md` #15·#16). `미측정`(측정했으나 값 없음)과 축이 -다르니 대체하지 말고 병기한다. 확인 후에는 `[추론]`을 떼고 `파일:라인` 근거로 바꾼다. - -## 중단 시에도 먼저 쓴다 - -**`미검증·불명확` 절이 모든 누락의 종착지다.** 에이전트 전원 실패로 중단하는 경우에도 -이 파일을 그 1개 절만으로 **먼저 쓴 뒤** 보고한다 — 중단하면 흔적이 채팅에만 남아 -폴더를 여는 사람이 상황을 알 수 없다. - -작성 후 산출 경로와 P0 항목을 요약 보고한다. `_workspace/`는 감사 추적용으로 보존한다. - -> `.md` 200줄 상한(`rules.md` #4)은 이 보고서에도 적용된다. 넘으면 영역별로 분할하고 -> 요약 본문에서 상대경로로 링크한다. diff --git a/.claude/skills/orchestrate-ptop-harness/references/test-scenarios.md b/.claude/skills/orchestrate-ptop-harness/references/test-scenarios.md deleted file mode 100644 index 1958825..0000000 --- a/.claude/skills/orchestrate-ptop-harness/references/test-scenarios.md +++ /dev/null @@ -1,42 +0,0 @@ -# 테스트 시나리오 — orchestrate-ptop-harness - -## 정상 흐름 — "PTOP 전체 점검" 요청 - -1. Phase 1-0 대상 확인 통과 (PTOP 분석 대상이 발화에 있음) -2. Phase 1-1 `_workspace/` 에 산출물 `01`~`06` 이 하나도 없음 → **초기 실행** - (폴더 자체는 있어도 된다 — 채점·로그 파일만 있는 경우가 여기에 해당) -3. Phase 1-2 에이전트 3인 가용성 확인 통과 -4. Phase 1-4 승인 4항 제시 → 승인 — ①이동·삭제분 ②덮어쓰기분 ③생성분(`01~06` + `00_PTOP_HARNESS_SUMMARY.md` - + 부산출물 `01a~01e`·`04a_dependency_analysis.csv`) ④작업공간 관리 파일(`_workspace/`, `_progress.md`) -5. Phase 2 `ptop-lead`·`build-devops-engineer` 병렬 기동 (담당 스킬·산출 경로 모두 절대경로로 전달) -6. Phase 3 lead **완료 알림 수신 후** `01_ptop_architecture.md` + "불명확 — 확인 필요" 절 확인 → - `ptop-developer` 기동 -7. Phase 4 전원 완료 알림 후 교차 확인 질문 2건 -8. Phase 5 `00_PTOP_HARNESS_SUMMARY.md` 작성 → P0 요약 보고 - -## 에러 흐름 — `build-devops-engineer`가 `ILSOS_All.sln` 파싱 실패로 2회 연속 실패 - -1. 실패 판정 기준 ①(에러 종료) 성립 → `_progress.md`에 `시도 1/2` 기록 -2. 같은 `Agent` 재호출 → 또 실패 → `시도 2/2` → **실패 확정** -3. 빌드 영역 없이 아키텍처·구현만으로 진행 -4. Phase 4에서 죽은 에이전트에는 `SendMessage`하지 않고, 빌드 관련 교차 질문을 `미검증`으로 기록 -5. Phase 5 `00_PTOP_HARNESS_SUMMARY.md`의 `미검증·불명확` 절에 - "빌드 분석 누락 — sln 파싱 실패 2회"를 명시 -6. 사용자에게 **누락을 먼저** 알림 - -## 부분 재실행 흐름 — "아키텍처만 다시" - -1. Phase 1-1 `01`~`06` 중 하나 이상 있음 + 부분 수정 요청 → **부분 재실행** -2. Phase 1-5 원장 초기화 — 지목된 `ptop-lead`는 `진행중`, **지목되지 않은 `ptop-developer`· - `build-devops-engineer`는 `생략 — 이전 산출물 재사용`** 으로 적는다(상태 enum → `data-protocol.md`) -3. `ptop-lead`만 재기동. `_workspace_prev/`로 옮기지 **않는다** -4. Phase 3은 developer가 `생략` 이므로 기동하지 않고 넘어간다 (지목되지 않았다) -5. Phase 4는 `생략` 인 두 에이전트에 `SendMessage`를 보내지 않고, 그 산출물을 **직접 읽어** - 교차 확인 질문에 답한다 → `이전 실행 산출물에서 확인(YYYY-MM-DD)`. `미검증`이 아니다 -6. `01` 갱신 후 `02`·`03` 연쇄 재실행 여부를 사용자에게 질의 -7. 거절 시 두 파일 첫 줄에 `이전 실행 결과 재사용 — 01 갱신으로 정합성 미확인(YYYY-MM-DD)` 표기 - -## 전원 실패 흐름 - -에이전트 3인이 모두 실패해도 `00_PTOP_HARNESS_SUMMARY.md`를 `미검증·불명확` **1개 절만으로 먼저 쓴 뒤** -보고한다. 중단하면 흔적이 채팅에만 남아 폴더를 여는 사람이 상황을 알 수 없다. diff --git a/.claude/skills/ptop-deliverables/SKILL.md b/.claude/skills/ptop-deliverables/SKILL.md deleted file mode 100644 index c0e30e6..0000000 --- a/.claude/skills/ptop-deliverables/SKILL.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -name: ptop-deliverables -description: >- - LGES OC5 PtoP Welder 전용 산출물 자동 생성·갱신 스킬. - 프로젝트 소스를 분석해 docs/[Ubisam산출물]/ 하위 MD 산출물(색상 디자인 포함)을 - 생성하거나 최신화한다. 다른 PC에서는 `ubisam-deliverables` 스캐폴딩을 먼저 돌린 뒤 - 이 스킬로 전체 산출물을 재생산한다 (`docs/[Ubisam산출물]/`는 `.gitignore` 제외라 clone 직후 없다). "ptop 산출물", "PLC 신호정의서/기능명세서/시퀀스 인터락 정의서 갱신", - "소스 기준으로 설계 산출물 최신화", "코드 보고 설계문서 다시 뽑아줘", "/ptop-deliverables", 그리고 **소스 기준 재생산 후속 표현** - ("설계 MD 다시 뽑아줘", "소스 갱신분 반영", "이전 산출물 기반으로") 시 사용. - **입력이 PTOP 소스코드일 때만** 쓴다. 맨손 "업데이트"·"다시 실행"만으로는 이 스킬을 고르지 않는다 — - 대상을 먼저 확인한다. - 구분 — 트리를 새로 까는 스캐폴딩은 `ubisam-deliverables`, 이미 있는 타사 문서를 Ubisam - 양식으로 재생산하는 것은 `ubisam-deliverable-rebuild`, enum 조회만이면 `ubisam-format-map`, - **PTOP 아키텍처·구현·빌드 분석**은 `orchestrate-ptop-harness`. ---- - -# PTOP 산출물 자동 생성 SKILL - -LGES OC5 PtoP Welder(`ILSOS_PrismaticRD_PTOP`) 전용. -소스를 분석해 6단계 산출물 MD를 **Ubisam 디자인 시스템**(배너·뱃지·진행률 포함) 기준으로 생성한다. - -## 참조 맵 - -| # | 파일 | 용도 | -|---|---|---| -| D | [references/design-system.md](references/design-system.md) | 색상 팔레트·배너·뱃지 HTML 템플릿 | -| S | [references/source-map.md](references/source-map.md) | 소스 파일 → 산출물 필드 매핑 | - -## 소스 진실원 — 읽는 순서 - -다른 PC에서 실행 시 아래 파일을 순서대로 읽어 산출물을 채운다. - -| 순서 | 파일 경로 | 추출 정보 | -|---|---|---| -| 1 | `Machines/ILSOS_PrismaticRD_PTOP/Device/PLC/PLCController.Address.cs` | BIT/WORD 신호 enum 전수 | -| 2 | `Machines/ILSOS_PrismaticRD_PTOP/EquipmentSetup.cs` | 디바이스 등록·메뉴·뷰 목록 | -| 3 | `Machines/ILSOS_PrismaticRD_PTOP/Sequences/SeqAutoRunPTOP.cs` | 시퀀스 노드·인터락·TactTime | -| 4 | `Machines/ILSOS_PrismaticRD_PTOP/Device/IO/PAIX_PTOP.cs` | DI/DO 채널 맵 | -| 5 | `docs/architecture.md` | 플랫폼·모션·디바이스 개요 | -| 6 | `docs/[Ubisam산출물]/_meta/project.yaml` | 프로젝트 코드·팀 정보 | - -## 진입 가드 (먼저 확인) - -사용자 발화에 **대상이 무엇인지**(소스코드 / 특정 문서 파일 / 미지정) 드러나지 않으면 -**어떤 파일도 만들거나 고치지 말고 되묻는다.** "산출물 업데이트해줘"·"다시 실행해줘"·"보완해줘" 같은 발화는 -이 스킬·`ubisam-deliverable-rebuild`·`ubisam-deliverables` 중 무엇이든 될 수 있고, -잘못 고르면 사용자가 원하지 않은 파일이 대량으로 덮어써진다. - -되물을 것: "① 소스코드 기준으로 설계 MD를 다시 뽑을까요, ② 기존 xlsx/pptx 문서를 Ubisam 양식으로 -재생산할까요, ③ 산출물 폴더 트리를 새로 깔까요?" - -생성·덮어쓸 파일 목록을 먼저 제시하고 승인을 받은 뒤 쓴다 (`rules.md` #2). - -## 실행 절차 - -### STEP 0 — 진입 체크 -`docs/[Ubisam산출물]/` 폴더 존재 여부 확인. -없으면 `/ubisam-deliverables` 스캐폴딩을 먼저 실행 후 재진입. - -### STEP 1 — 소스 분석 -소스 진실원 6개를 순서대로 읽어 추출한다: -- PLC BIT/WORD 신호 목록 (eBitInput/Output, eWordInput/Output) -- 등록 디바이스 (PLC·IO·Laser·Scanner·Motion·Vision) -- 메뉴·뷰 트리 (`RegisterViews` — `AddSubMenu(CommonViewIds.*, UC)` 는 2인자라 권한이 없지만, - **`MainMenu` 생성자 3번째 인자가 `PermissionLevel` 이다**. 메인메뉴 8건이 값을 가진다 — - `EquipmentSetup.cs:261,266,289,302,310,318,323,330`. 기능명세서 §메뉴구조의 `권한` 열은 여기서 채운다) -- 시퀀스 노드 흐름 + 인터락 조건 + 정지/에러 처리 -- TactTime 상수 (지연 ms, 타임아웃 s, 루프 슬립) -- DI/DO 채널 번호·신호명·설명 (PAIX_PTOP.cs) - -### STEP 2 — 산출물 MD 생성/갱신 - -[design-system.md](references/design-system.md) 배너·뱃지 템플릿을 적용해 -아래 파일을 **없으면 생성, 있으면 내용 갱신**한다. - -| 산출물 | 경로 | 채움 소스 | -|---|---|---| -| PLC-PC 신호정의서 | `02.설계/IO_DB설계/PLC_PC_인터페이스_신호정의서.md` | PLCController.Address.cs | -| 모션축·IO 맵 정의서 | `02.설계/IO_DB설계/모션축_IO맵_정의서.md` | EquipmentSetup + PAIX_PTOP | -| 기능명세서 | `02.설계/UIUX_기능설계/기능명세서.md` | EquipmentSetup.RegisterViews | -| 시퀀스·인터락 정의서 | `02.설계/시퀀스_인터록/제어시퀀스_인터락_정의서.md` | SeqAutoRunPTOP.Builder | -| TactTime 산정서 | `02.설계/시퀀스_인터록/TactTime_산정서.md` | SeqAutoRunPTOP 지연 상수 | - -각 파일 구조: **배너(진네이비) → 부제(파랑) → 내용 테이블/mermaid → enum 요약** - -### STEP 3 — _task 카드 갱신 -`01~06` 각 `_task.md` 상태·진행률을 현황 반영해 갱신. -적용 디자인: 상태 뱃지 + 유형 뱃지 + `` 진행률 바. - -### STEP 4 — 분석 로그 기록 -`[분석]/YYYY_MM_DD_PTOP설계산출물-분석.md` 작성. -내용: 소스→필드 매핑 표 + 미확정 항목 목록 + 진실원 인덱스. - -## 불변 규칙 -- **비침습**: `docs/[Ubisam산출물]/` 밖은 읽기만. 소스·CLAUDE.md 수정 금지. -- **MD 200줄 상한** (`rules.md` #4): 초과 시 분할 + 상대경로 링크. -- **출처 명시**: 채운 값마다 `— 출처: 파일명:심볼` 주석. -- **미확정 표기**: 주소·행정·속도 등 미확정값 → `(제안)`. -- **추론 표기**: 소스에서 확인하지 않고 채운 값·해석은 `[추론]` 접두 (`rules.md` #15·#16). - `(제안)`(진실원 자체가 없음)과 축이 다르다 — 확인 후에는 표기를 떼고 `— 출처: 파일:심볼`로 바꾼다. -- **멱등**: 재실행 시 배너·뱃지는 교체, 테이블 데이터는 행 추가/갱신. -- **md ↔ xlsx 공존 규칙**: 같은 슬롯에 `기능명세서.md`(이 스킬)와 `기능명세서.xlsx` - (`ubisam-deliverables/references/build_02설계_xlsx.py`)가 공존할 수 있다. **소스 기준 최신값의 진실원은 `.md`**이고, `.xlsx`는 배포용 스냅샷이다. - ⚠ **md→xlsx 자동 동기화 수단은 없다.** `build_02설계_xlsx.py`는 데이터가 코드에 하드코딩된 - 무인자 스크립트라 md를 입력으로 받지 못한다. 어긋나면 그 스크립트의 데이터 블록을 md 기준으로 - **함께 고친 뒤** 재실행한다. -- **Aurora 고정 문구**: "운영 SW는 LG PRI의 Aurora 플랫폼으로 개발한다." - -> 소스 진실원 6종 읽기 + MD 5종 생성 + `_task` 6장 갱신은 10분을 넘긴다 — -> **STEP 전환마다 지금 어느 단계인지 한 줄로 보고한다**(`rules.md` #10). -> -> 단독 호출로 마무리할 때: 보고는 `rules.md` #11~13 출력 형식(수정 줄=초록 화살표, 단어=주황, 미변경=기본색)을 -> 따르고, 끝에 관련 `.md`를 갱신할 부분이 있는지 묻는다(`rules.md` #6). diff --git a/.claude/skills/ptop-deliverables/references/design-system.md b/.claude/skills/ptop-deliverables/references/design-system.md deleted file mode 100644 index b19862b..0000000 --- a/.claude/skills/ptop-deliverables/references/design-system.md +++ /dev/null @@ -1,134 +0,0 @@ -> **팔레트·뱃지 정의의 진실원은 `ubisam-deliverables/references/08-design-system.md`다.** -> 값이 갈리면 그쪽이 맞다. 이 파일은 PTOP 전용 추가분과 사용 예시만 기술한다. - -# PTOP 산출물 — Ubisam 디자인 시스템 - -> MD 산출물에 적용하는 HTML 색상 템플릿 모음. -> VS Code Markdown Preview / Typora / GitLab 렌더링 기준. - ---- - -## 색상 팔레트 - -| 구분 | 이름 | 색 코드 | 용도 | -|---|---|---|---| -| 배너 | 진네이비 | `#1F4E78` | 문서 최상단 제목 배너 | -| 헤더 | 파랑 | `#2E75B6` | 배너 하단 부제 바, 섹션 강조 | -| 연파랑 | — | `#DDEBF7` | 테이블 홀수 행 참조 (xlsx 전용, MD 생략 가능) | -| 상태·해야 할 일 | 회색 | `#757575` | 미착수 | -| 상태·분석 진행 | 청색 | `#1976D2` | 선택됨 | -| 상태·업무 진행중 | 파랑 | `#1565C0` | 진행 중 | -| 상태·진행 완료 | 연두 | `#689F38` | 완료 | -| 유형·오류수정 | 빨강 | `#D32F2F` | — | -| 유형·불합리 | 주황 | `#F57C00` | — | -| 유형·미팅 | 청록 | `#00796B` | 1.분석/협의 | -| 유형·설계 | 연두 | `#689F38` | 2.설계 | -| 유형·개발 | 파랑 | `#1976D2` | — | -| 유형·제작 | 남파랑 | `#283593` | 3.제작 | -| 유형·입고셋업 | 보라 | `#7B1FA2` | 4.셋업 | -| 유형·적용 및 모니터링 | 하늘 | `#0288D1` | 5.양산 | -| 유형·요청대응 | 남색 | `#1A237E` | 6.CS | - ---- - -## 1. 문서 배너 (최상단) - -산출물 MD 파일 1번째 줄부터 적용. - -```html -
-문서 제목 -
-
-근거: 소스 경로  ·  Aurora 2.0 / .NET 4.8.1 / WPF -
-``` - ---- - -## 2. 상태 뱃지 - -`_task.md` 상태 필드에 사용. 값에 맞춰 색 코드 교체. - -```html - -해야 할 일 - - -분석 진행 - - -업무 진행중 - - -진행 완료 -``` - ---- - -## 3. 유형 뱃지 - -```html -오류수정 -불합리 -미팅 -설계 -제작 -입고셋업 -개발 -적용 및 모니터링 -요청대응 -``` - -> 뱃지는 **9종**이며 `ubisam-format-map/SKILL.md` §2 의 일감 유형 enum과 1:1 대응한다. -> enum을 늘리거나 줄이면 이 블록도 **같은 편집에서** 고친다. - ---- - -## 4. 진행률 바 - -`` 태그 + 텍스트 병기 (렌더러 호환). - -```html - 0% -``` - ---- - -## 5. _task.md 전체 템플릿 - -```markdown -
-N.단계명 — LGES OC5 PtoP Welder -
-
-LGES_PTOP_01_20260605-XXXX -
- -| 필드 | 값 | -|---|---| -| 유형 | 유형명 | -| 상태 | 상태명 | -| 담당자 / 참조자 | {미정} / {미정} | -| 진행률 | **N%** | -| Hashtag | 태그1 / 태그2 | -``` - ---- - -## 6. 산출물 섹션 헤더 - -산출물 MD 내 시트 구분 헤더. - -```markdown -## 시트① 제목 -``` - ---- - -## 7. 미확정·제안 강조 - -```markdown -> [!NOTE] -> 아래 값은 소스 enum offset 기반 `(제안)`. PLC 맵 CSV 입수 후 확정. -``` diff --git a/.claude/skills/ptop-deliverables/references/source-map.md b/.claude/skills/ptop-deliverables/references/source-map.md deleted file mode 100644 index f574a3a..0000000 --- a/.claude/skills/ptop-deliverables/references/source-map.md +++ /dev/null @@ -1,141 +0,0 @@ -# PTOP 소스 → 산출물 필드 매핑 - -> 이 파일은 소스 파일과 산출물 필드 간 1:1 매핑 인덱스. -> 다른 PC에서 스킬 실행 시 이 파일을 보고 어떤 소스를 읽어야 할지 판단한다. - ---- - -## A. PLC-PC 인터페이스 신호정의서 - -출력: `02.설계/IO_DB설계/PLC_PC_인터페이스_신호정의서.md` - -| 시트 | 소스 파일 | 읽어야 할 심볼 | -|---|---|---| -| 통신 사양 | `Device/PLC/PLCContoller.Config.cs` | `PLCControllerPTOP` 생성자 인자(`ePLCNetType`, `PLCMMapFileType`, `isSimul`) — 이 파일은 18줄이며 주소 정의는 없다 | -| PC→PLC (Write) | `Device/PLC/PLCController.Address.cs` | `eBitOutput`, `eWordOutput` enum 전수 | -| PLC→PC (Read) | `Device/PLC/PLCController.Address.cs` | `eBitInput`, `eWordInput` enum 전수 | -| 핸드셰이크 시퀀스 | `Sequences/SeqAutoRunPTOP.cs` | `CheckPageNo`, `CheckRecipeNoComp`, `CheckPageNoComp`, `WaitWeldingStart`, `WriteWeldComplete` | - -**PLC 주소 규칙** — ⚠ **소스에 없는 값이다.** `M70000`·`D70000`·`D70500`은 `.cs` 전체에서 0건이고, -근거는 분석 문서(`docs/분석/2026/06/17/171312_plc_map_io_direction_and_enum_alignment.md`)뿐이며 -그 문서와 `docs/분석/2026/06/20/141528_산출물문서_분석_및_PTOP_채움안.md`(**06/20 폴더다 — 06/17에는 없다**)가 -서로 다르게 기술한다. **산출물에 옮기기 전 소스로 재확인하고 `파일:라인`을 -병기하라. 확인되지 않으면 `미확인`으로 남긴다** (`rules.md` §검증·표기 판정표의 토큰만 쓴다). - -- `eBitOutput` offset → `M70000 + offset` -- `eBitInput` offset → `M70500 + offset` -- `eWordOutput` offset → `D70000 + offset` -- `eWordInput` offset → `D70500 + offset` -- 두 번째 블록(0x65~, 양극 P) → `M70600~` (현재 미사용) - ---- - -## B. 모션축·IO 맵 정의서 - -출력: `02.설계/IO_DB설계/모션축_IO맵_정의서.md` - -| 시트 | 소스 파일 | 읽어야 할 심볼 | -|---|---|---| -| 통신·제어 구성 | `EquipmentSetup.cs:138` | `RegisterDevices(IDeviceRegistry registry)` 내 `registry.Register(...)` 호출. **주석 처리된 것이 다수다**(OCT·LBAD·CellTracker 등) — 활성 등록만 센다(현재 3건) | -| 모션축 정의 | `docs/architecture.md §4` | AuroraACS(X/Y), AuroraMotionBoard(Z). **`RTC`(Scanner)는 이 문서에 0건** — 출처는 `ubisam-format-map/SKILL.md` §6 `PTOP 채움 시 참고값` 의 주요 디바이스 문장이다 | -| I/O 맵 DI | `Device/IO/PAIX_PTOP.cs` | `ePrismaticDIAddress` enum — 채널 번호·신호명 | -| I/O 맵 DO | `Device/IO/PAIX_PTOP.cs` | `ePrismaticDOAddress` enum — 채널 번호·신호명 | - -**모션축 주의사항**: -- X/Y 행정·속도·Home 방식 = 소스에 없음 → 전부 `(제안)` 표기. -- `AuroraACS` = EtherCAT SPiiPlus. `AuroraMotionBoard` = **Ajin 모션 보드** - (`AuroraDevices/AuroraMotionBoard/Ajin/AJINDevice.cs`·`AJINMotor.cs` — 벤더 구현이 이것 하나뿐이다). -- ⚠ **런타임 벤더 선택은 모션이 아니라 IO 보드 쪽이다.** `eIOBoardType`(`Ajin`·`PAIX`·`ACS`)은 - `AuroraDevices/AuroraIO/IODevice.cs:18` 정의이고 `:154-158`에서 `IOUnitConfig.BoardType` 으로 분기한다. - **IO 보드 벤더를 `Ajin`으로 단정하지 말 것** — PTOP 실제 IO는 `PAIX_PTOP` 이다. - 모션 보드 벤더 주의문과 혼동하지 않는다(둘은 다른 디바이스다). - ---- - -## C. 기능명세서 / UI 설계 - -출력: `02.설계/UIUX_기능설계/기능명세서.md` - -| 탭 | 소스 파일 | 읽어야 할 심볼 | -|---|---|---| -| 메뉴 구조 | `EquipmentSetup.cs:256` | `RegisterViews(IViewManager manager)` 내 `AddSubMenu(CommonViewIds.*, UserControl)`. **총 26건 중 8건이 주석 처리** → **활성 18건만 센다**(위 `RegisterDevices` 행과 같은 규칙). ⚠ `MenuId`·`ViewType`·`AuthLevel` 은 **소스에 없는 심볼이다** — 지어내지 마라 | -| 메뉴 권한 | `EquipmentSetup.cs:261,266,289,302,310,318,323,330` | **`AddSubMenu` 는 2인자라 권한이 없지만 `MainMenu` 생성자 3번째 인자가 `PermissionLevel` 이다.** 메인메뉴 8건이 값을 가진다 — NONE ×6 / `:318` Device=LEVEL3 / `:323` Setting=LEVEL1. (`:288` 주석의 LEVEL4는 비활성, `:337` StreamDevice는 2인자 오버로드이며 `UseStream` 조건부라 권한 인자가 없다) | -| MainView | `Views/Main/UCMainAutoRun*.cs` | 버튼·이벤트·바인딩 목록 | -| RecipeView | `EquipmentSetup.cs` 등록부 | `UCRecipe`, `UCRecipeChangeHistory` — **공유 컴포넌트**이며 PTOP `Views/` 아래에 없다 | -| ManualView | `EquipmentSetup.cs` 등록부 | `UCManualScannerOperation`, `UCManualModelFinder` — 공유 컴포넌트 | -| MonitoringView | `EquipmentSetup.cs` 등록부 | `UCIOInterfaceView` 등 — 공유 컴포넌트 | -| DeviceView | `EquipmentSetup.cs:318-319`·`:310-314` | `CommonViewIds.Device`(`DeviceSettingView`) + **Monitoring 메뉴의** `PLCBitMonitoring`·`PLCWordMonitoring`·`IOInterfaceView`. 탭 내용 기준은 `05-form-schemas.md` 8탭 표의 `DeviceView` 행 (`StreamDevice`는 `:337` 별도 메인메뉴이며 SettingView 탭 소속) | -| SettingView | `EquipmentSetup.cs` 등록부 | `CommonViewIds.Setting`·`LogSetting`·`AutoBackupView` 등록 항목 | -| VisionView | `EquipmentSetup.cs:342-343` | **`(해당없음)` — AuroraVision 미사용.** `// Vision (미사용)` + `//VisionFactory.RegisterViews(manager);` 주석 처리. `CommonViewIds.Scanner`·`PixelResolution`(`:303`·`:306`)은 비전 탭이 아니라 **Calibration 메뉴**(`:302`) 소속이다 | -| OverView | `docs/architecture.md` | `CommonViewIds` 에 대응 메뉴는 없다 — 이 탭은 등록부가 아니라 **SW 개요**(플랫폼·OS·.NET·모션·레이저·PLC·비전)로 채운다 | -| Sequence 흐름 | `Sequences/SeqAutoRunPTOP.cs` | Builder() 노드 목록 순서대로 | - -> PTOP의 `Views/` 하위는 **`Main/`과 `Model/` 둘뿐이다.** Recipe·Manual·Monitoring 화면은 -> 공유 컴포넌트라 `EquipmentSetup.cs`의 `AddSubMenu(...)` 등록부에서 타입을 확인해야 한다. - -**8탭 고정** (xlsx ref 호환): OverView / MainView / RecipeView / ManualView / DeviceView / SettingView / VisionView / Sequence 흐름 - -> ⚠ **탭 목록·탭별 내용의 상위 진실원은 `ubisam-deliverables/references/05-form-schemas.md` -> §`C. 기능명세서 / UI 설계` 의 8탭 표다.** -> 위 표는 "그 탭을 채우려면 어느 소스를 읽는가"만 말한다. 두 문서가 어긋나면 -> `05-form-schemas.md` 를 기준으로 삼고 **같은 편집에서 이 표를 맞춘다** (`docs/harness-ptop.md` §소비처 확인 의무). - -> 위 표는 이 8탭을 **전부** 담고 있다. 추가로 있는 `메뉴 구조`·`MonitoringView` 행은 탭이 아니라 -> **탭을 채우기 위해 읽을 진실원**이다. 탭 수를 셀 때 포함하지 않는다. - ---- - -## D. 제어 시퀀스·인터락 정의서 - -출력: `02.설계/시퀀스_인터록/제어시퀀스_인터락_정의서.md` - -| 섹션 | 소스 파일 | 읽어야 할 심볼 | -|---|---|---| -| 메인 시퀀스 노드 흐름 | `SeqAutoRunPTOP.cs` | `AddAction`(17)·`AddDecision`(4)·`AddSubsequence`(3)와 `Flows(...)`(6). ⚠ `AddNode`·`AddTransition` 은 **소스에 없는 심볼이다**(Aurora API가 아니다) | -| 단계별 동작 요약 | `SeqAutoRunPTOP.cs` | 각 노드 메서드 구현 첫 줄 주석·로그 | -| 인터락 정의 | `Settings/LaserInterlockSetting.cs` | `HeadThetaInterlockEnabled`, `HeadThetaTolerance` | -| 인터락 정의 (추가) | `SeqAutoRunPTOP.cs` | `LaserInterlock` 처리 | -| 중알람 감시 | `Sequences/Monitoring/SeqAlarmMonitor.cs` | `PLC_HEAVY_ALARM_STATUS` 처리 (정의는 `PLCController.Address.cs`) — `SeqAutoRunPTOP.cs`에는 없다 | -| 정지/에러 처리 | `SeqAutoRunPTOP.cs` | `OnStopped`, `OnForceError`, `ResumeMode` | - -**Resume(bit15) 흐름**: `PLC_WELD_READY_REQ(0x0F)` 수신 → 팝업 + Auto→Manual 전환 → `PC_WELD_READY_ACK(0x0F)` ON → 1사이클 후 OFF. -> 출처 주의 — 네 곳으로 나뉜다. 시퀀스 파일만 뒤지면 못 찾는다. -> `UCMainAutoRunViewModel.cs:209`=수신 · `:270`=ACK ON · `:271-277`=**1초 펄스 OFF(`DispatcherTimer`)** · -> `SeqAutoRunPTOP.cs:875`=사이클 종료 OFF. **OFF 경로가 둘이다** — 1초 타이머와 사이클 종료. - ---- - -## E. TactTime 산정서 - -출력: `02.설계/시퀀스_인터록/TactTime_산정서.md` - -> **아래 상수는 반드시 소스에서 재확인하고 `파일:라인`을 병기한다.** 표에 적힌 값은 마지막 확인 시점의 -> 것이고, 심볼이 사라지거나 값이 바뀌었을 수 있다. 찾지 못하면 지어내지 말고 `미확인`으로 남긴다. - -| 단위동작 | 소스 파일 | 상수/값 | 최종 확인 | -|---|---|---|---| -| Gate ON delay | `SeqAutoRunPTOP.cs` | `laserEmissionGateDelayMs` | 실재 확인 (2026-08-03) | -| Jump 복귀 | `SeqAutoRunPTOP.cs` | `Thread.Sleep(500)` | 실재 확인 (2026-08-03) | -| Pre/Post Scout | `SeqAutoRunPTOP.cs` | `SCOUT_PROCEED_DELAY_MS` | 실재 확인 (2026-08-03) | -| 실제 발진 | `SeqAutoRunPTOP.cs` | 로그 `"TactTime: [Nms]"` — **런타임 값. 실측 없이 기재 금지** | — | -| Page 검증 지연 | `SeqAutoRunPTOP.cs` | 해당 상수를 소스에서 찾아 기입 | 미확인 | -| 준비 응답 지연 | `SeqAutoRunPTOP.cs` | 해당 상수를 소스에서 찾아 기입 | 미확인 | -| 완료비트 지연 | `SeqAutoRunPTOP.cs` | 해당 상수를 소스에서 찾아 기입 | 미확인 | - ---- - -## F. _task.md 진행률 기준 (현황 기준) - -> **이 표는 실행 시점에 재산출한다.** 아래 값은 작성 당시 스냅샷이며, 그대로 복사하면 안 된다. -> 각 단계 폴더의 실제 산출물 존재 여부를 세어 진행률을 다시 계산하라. - -| 단계 | 상태 | 진행률(스냅샷) | 근거 | -|---|---|---|---| -| 1.분석/협의 | 미산출 | 미산출 — 실행 시 계산 | 슬롯 폴더의 실제 산출물 수로 산정 | -| 2.설계 | 미산출 | 미산출 — 실행 시 계산 | 〃 | -| 3.제작 | 미산출 | 미산출 — 실행 시 계산 | 〃 | -| 4.셋업 | 미산출 | 미산출 — 실행 시 계산 | 〃 | -| 5.양산 | 미산출 | 미산출 — 실행 시 계산 | 〃 | -| 6.CS | 미산출 | 미산출 — 실행 시 계산 | 〃 | - -> 이 값은 스킬 실행 시점 기준. 재실행 시 소스·폴더 현황 재확인 후 갱신. diff --git a/.claude/skills/ubisam-deliverable-rebuild/SKILL.md b/.claude/skills/ubisam-deliverable-rebuild/SKILL.md deleted file mode 100644 index 12f4c5a..0000000 --- a/.claude/skills/ubisam-deliverable-rebuild/SKILL.md +++ /dev/null @@ -1,191 +0,0 @@ ---- -name: ubisam-deliverable-rebuild -description: >- - 타사 양식으로 받은 기존 산출물(Doc/산출물문서의 xlsx·pptx·docx)을 Ubisam 협업관리 - 양식으로 분석·재배치·재생산·검증하는 3에이전트 오케스트레이터. "이 문서 Ubisam 양식으로 - 바꿔줘", "타사 산출물 재생산", "협업관리 양식으로 재배치", "산출물 채움", - "이 xlsx를 Ubisam 단계로 매핑", 그리고 **재생산에 대한** 후속 표현("산출물 재실행", - "재생산 다시", "이 문서만 다시", "재생산 결과 보완", "이전 재생산 기반으로") 시 이 스킬을 쓴다. - 구분 — 빈 트리를 새로 까는 스캐폴딩은 `ubisam-deliverables`, PTOP 소스코드를 읽어 - 설계 MD를 뽑는 것은 `ptop-deliverables`, 양식 enum 조회만이면 `ubisam-format-map`, - **PTOP 아키텍처·구현·빌드 분석**은 `orchestrate-ptop-harness`다. - 맨손 "업데이트"·"다시 실행"만으로는 이 스킬을 고르지 않는다 — 대상 문서를 먼저 확인한다. ---- - -# ubisam-deliverable-rebuild — 타사 양식 → Ubisam 양식 재생산 오케스트레이터 - -**입력이 이미 존재하는 문서일 때** 쓰는 하네스다. 그 문서를 해부해 Ubisam 6단계 슬롯으로 재배치하고 -Ubisam 양식으로 다시 찍어낸 뒤 검증한다. - -- 실행 모드: **서브 에이전트 + 점진적 생성-검증 루프** -- 팀원: `ubisam-analyst` → `ubisam-producer` ↔ `ubisam-qa` (모두 `model: "opus"`) -- 공유 스킬: `ubisam-format-map` (enum·스키마·슬롯 — 모든 팀원이 먼저 읽음) -- 작업공간: `docs/[Ubisam산출물]/_workspace/`, 최종 산출물은 6단계 폴더 또는 사용자 지정 경로 - (**사용자 지정 경로를 쓴 경우** `00_rebuild_summary.md`에 실제 배치 경로표를 남기고, - qa는 검증항목 #1(슬롯 누락)을 그 표 기준으로 판정한다) - -## 형제 스킬과의 경계 - -| 상황 | 쓸 스킬 | -|---|---| -| 산출물 트리가 아예 없음 → 폴더·`_meta`·일감 카드 스캐폴딩 | `ubisam-deliverables` | -| **기존 타사 문서**를 Ubisam 양식으로 재생산 | **이 스킬** | -| PTOP **소스코드**를 읽어 설계 산출물 MD 생성 | `ptop-deliverables` | -| enum·슬롯 값만 조회 | `ubisam-format-map` | - -## 도구 사용 규칙 - -이 환경에는 `TeamCreate`/`TeamDelete` 도구가 **없다**. 팀은 아래 방식으로 구성한다. - -- 팀원 기동: `Agent` 도구 — `subagent_type`에 에이전트 이름, `model: "opus"`, 병렬 구간은 `run_in_background: true` -- 팀원 간 소통: `SendMessage` (`to`에 에이전트 **이름** 지정) -- 진행 공유: `docs/[Ubisam산출물]/_workspace/_progress.md` 파일(진실원). 태스크 도구는 가용 시 보조 -- 산출물 전달: 파일 (`docs/[Ubisam산출물]/_workspace/`) - -## Phase 0: 컨텍스트 확인 - -> **경로 인용 주의.** `docs/[Ubisam산출물]/`의 대괄호는 `Glob`/`Grep` **패턴**에서 문자클래스로 -> 해석돼 **에러 없이 0건**을 낸다(실측). 존재 확인은 Bash에서 따옴표로 감싸거나, -> `Grep`/`Glob`의 `path` 인자(리터럴)로 하거나, 패턴을 `docs/\[Ubisam산출물\]/…`로 이스케이프한다. -> 상세 → `ubisam-deliverables/references/00-harness.md` §경로 인용 의무. - - -0. **진입 가드 2건. 둘 다 통과해야 Phase 1로 간다.** - - **대상 미지정** — 사용자 발화에 어떤 문서를 재생산할지 없으면(예: "산출물 업데이트해줘") - **아무 파일도 만들지 말고 되묻는다.** `Doc/산출물문서/`에 후보가 여럿이므로 임의로 고르면 - 원하지 않은 문서에 3에이전트 풀런이 돌아간다. - - **에이전트 미등록** — `ubisam-analyst`/`ubisam-producer`/`ubisam-qa`가 `Agent` 도구의 - subagent_type 목록에 없으면 시작하지 말고 "프로젝트 에이전트 미등록 — 세션 재시작 필요"를 - 보고하고 중단한다. `.claude/agents/`에 파일을 방금 추가했다면 세션 재시작 전까지 호출되지 않는다. - -1. 대상 문서와 작업 디렉토리를 정한다. 기본 작업공간 `docs/[Ubisam산출물]/_workspace/`. - -2. **실행 모드 판별** (승인 목록을 확정하기 위해 먼저 한다): - `docs/[Ubisam산출물]/_workspace/` 의 **산출물(`01_analyst_*`·`02_producer_*`·`03_qa_*`) 존재 여부**로 - 판별한다 — 폴더 존재만 보면 로그·메모만 있어도 오판정한다(PTOP 하네스와 동일 규칙). - - 하나도 없음 → **초기 실행** (Phase 1부터. 폴더가 있어도 초기 실행이다) - - 일부만 있음 + 전체 재생산 요청 → **이어서 실행.** 있는 것 재사용, 없는 것만 생성, 이동 없음 - - 부분 수정 요청("OO만 다시") → **부분 재실행** (해당 에이전트만 재호출) - - **새 입력 문서** 또는 "처음부터 다시" 명시 → **`전면`** (기존을 `_workspace_prev/`로 이동) - - 네 모드의 이름은 **`초기` / `이어서` / `부분` / `전면`** 이며, Phase 1·2에서 팀원에게 이 문자열 - 그대로 전달한다. `_workspace_prev/` 이동은 **오케스트레이터만** 하고 팀원은 하지 않는다 — - 팀원은 모드를 "기존 산출물을 재사용할지" 판단에만 쓴다. - -3. **스캐폴딩 필요 여부 판정.** `docs/[Ubisam산출물]/`가 없으면 `ubisam-deliverables` 스캐폴딩이 - 선행되어야 한다. 그 스킬이 만들 폴더·파일 목록도 아래 승인 대상에 **합산**한다. - -4. **승인 게이트.** 아래 **넷**을 **한 번에** 제시하고 승인받는다 (`rules.md` #2) — - ① 스캐폴딩분 ② 모드별 이동·덮어쓰기분(`_workspace_prev/` 이동 포함) ③ 재생산분 - ④ **작업공간 관리 파일**(`_workspace/` 생성, `_progress.md`, `01_analyst_*`·`02_producer_*`·`03_qa_*` 중간 로그). - ④를 빼면 `ubisam-producer.md`의 "승인 범위 밖 금지"와 충돌해 작업 로그조차 못 쓴다. - 모드 판별·스캐폴딩 판정을 승인보다 먼저 하는 이유는, 그러지 않으면 승인 목록이 - 실제 변경 범위와 어긋나기 때문이다. - -5. **스캐폴딩 실행** (3에서 필요하다고 판정된 경우에만). `ubisam-deliverables` 스킬의 A단계를 - 호출한다 — 대상이 이미 명시됐으므로 그 스킬의 진입 가드는 통과한다. - 그 스킬의 **진입 가드 승인과 A단계 0번 승인 모두** 위 4에서 통합으로 받았으므로 생략한다 - (승인을 두 번 걸지 않는다). - 완료를 확인한 뒤 다음 단계로 간다. 이 단계를 건너뛰면 producer가 - `docs/[Ubisam산출물]/{NN.단계}/`·`_meta/build_scripts/`에 쓰려는 순간 부모 폴더가 없어 실패한다. - -6. `docs/[Ubisam산출물]/_workspace/_progress.md`를 만든다. **행 단위는 `{에이전트}:{문서}` 다** — - 문서가 3건이면 analyst·producer·qa 각 3행씩 **9행**이다(Phase 2가 문서 1건당 producer 1기동이므로). - 문서별로 따로 세야 "같은 결함 2회" 상한이 문서 단위로 작동한다. 문서가 1건이면 3행이다. - 재시도 카운트(`시도 N/2`)의 **진실원이 이 파일**이다 — `TaskCreate`/`TaskUpdate`는 서브에이전트 - 컨텍스트에 없을 수 있어 도구에만 의존하면 횟수가 대화 맥락에만 남는다. 도구가 가용하면 병행 등록해도 된다. -7. `ubisam-format-map` 스킬을 로드해 양식 기준을 확보한다. - -> **Phase 1(analyst)부터** 시작한다. analyst를 건너뛰고 producer로 가면 매핑표가 없어 즉시 멈춘다. - -## Phase 1: 분석 (analyst) - -`Agent(subagent_type: "ubisam-analyst", model: "opus", run_in_background: true)` 로 기동. -**문서가 1건이어도 `run_in_background` 를 뺀다는 뜻이 아니다** — `to: "main"` 회신이 막힌다. -(아래 "문서가 여러 개면 병렬 기동"은 **개수**에 관한 말이지 이 플래그의 조건이 아니다.) -대상 문서별로 구조 해부 · 타설비 잔재 식별 · 6단계 슬롯 매핑을 요청한다. - -- 산출: `docs/[Ubisam산출물]/_workspace/01_analyst_{문서}.md` -- 산출 경로와 **진행 원장 `_progress.md` 경로**를 모두 **저장소 루트 기준 절대경로로 변환해서** 전달한다 — 서브에이전트의 셸 작업 디렉토리는 - 호출마다 초기화되므로 상대경로를 그대로 주면 파일이 엉뚱한 곳에 떨어지고, 실패 판정 ②(파일 미생성)가 - 오판한다. `_workspace/`가 없으면 먼저 만든다. -- **실행 모드(`초기`/`이어서`/`부분`/`전면`) 를 문자열 그대로 전달한다.** 빼면 analyst가 기존 - `01_analyst_*`를 재사용할지 판단할 근거가 없어 모드 판별이 승인 목록 산정에만 쓰이고 죽는다. -- 문서가 여러 개면 문서별로 병렬 기동(`run_in_background: true`)한다. 서로 의존이 없기 때문이다. - -## Phase 2: 재생산 ↔ 검증 (producer ↔ qa, 점진적) - -`Agent(subagent_type: "ubisam-producer", model: "opus", run_in_background: true)` 로 기동한다. -**qa 도 같은 형태로 기동한다.** `run_in_background` 를 빼면 `SendMessage` 의 `to: "main"` 회신이 -막힌다 — 그 값은 **백그라운드 서브에이전트 전용**이고, 세 에이전트 모두 오케스트레이터에 `main` 으로 보고한다. -**기동은 오케스트레이터 전담이다** — analyst·producer·qa는 서로를 띄우지 않는다. -Phase 1과 동일하게 **매핑표·산출·`_progress.md` 경로를 전부 저장소 루트 기준 절대경로로**, -그리고 **실행 모드(`초기`/`이어서`/`부분`/`전면`) 를 문자열 그대로** 전달한다 -(서브에이전트의 셸 작업 디렉토리는 호출마다 초기화된다). - -**문서가 여러 개면 문서 1건당 producer를 하나씩 기동한다.** 한 번에 다 맡기면 "1건 끝날 때마다 qa"라는 -아래 루프의 관측점이 사라져 점진 검증이 성립하지 않는다(전부 끝난 뒤 한꺼번에 검증하게 된다). - -producer는 매핑표대로 산출물을 재생산한다 — -**xlsx = `xlsxfill.py` 기반 신규 스크립트**(`_meta/build_scripts/`. 번들 `build_02설계_xlsx.py`는 데이터가 -하드코딩돼 있어 이 하네스에서 쓰지 않는다), pptx = `ubisam-ppt-make`, docx = `ubisam-docx`, md = 디자인 템플릿. - -**문서 1건이 끝날 때마다** `Agent(subagent_type: "ubisam-qa", model: "opus", run_in_background: true)` 를 -기동해 검증한다(`run_in_background` 는 위 규칙과 동일 — 빼면 `to: "main"` 회신이 막힌다). -전체 완성 후 일괄 검증하지 않는 이유는, 구조적 결함이 늦게 발견되면 이후 산출물 전부를 되돌려야 하기 때문이다. -qa에는 **원본·매핑표·산출물 3개 경로를 모두 절대경로로** 준다 — 하나라도 빠지면 교차 대조가 성립하지 않는다. - -- Critical/Major → producer가 수정 후 재검증. **같은 결함은 최대 2회까지만** 재작업을 요청하고, - 3회째에는 "미해결"로 확정해 사용자 판단 항목으로 올린다(무한 루프 방지). -- Minor → 로그에 기록만 하고 진행 - -## Phase 3: 종합·보고 - -`docs/[Ubisam산출물]/_workspace/00_rebuild_summary.md`를 작성한다 — 필수 섹션: -산출물 목록(경로) · 산출물별 stale 표기 · qa 판정 · **누락/미검증 항목과 사유** · 출처. -이 파일이 "보고서에 누락을 명시"의 종착지다. - -그 내용을 사용자에게도 요약 보고한다. -보고 시 `rules.md` #11~13 출력 형식을 따른다 — 수정 대상 줄은 초록 화살표(→), 단어 단위는 주황, 미변경은 기본색. -보고 끝에 **`docs/harness-ubisam.md`를 갱신할 부분이 있는지 묻는다**(`rules.md` #6). -문서 수가 많아 10분을 넘기므로 **Phase 전환마다 진행 상황을 한 줄로 보고한다**(`rules.md` #10). -중간 산출물(`docs/[Ubisam산출물]/_workspace/`)은 지우지 않고 보존한다 — 사후 감사 추적에 쓴다. - -## 데이터 전달 · 에러 핸들링 - -전달 = 파일(`_workspace/`) + `SendMessage`(`to`+`summary`+`message`) + `_progress.md`(진행 원장). -상세 표 2종 → [references/protocol.md](references/protocol.md) - -**에러 핵심 3가지:** -- 실패 = ①에러 종료 ②산출 파일 미생성 ③빈 파일·헤더만. **지연은 실패가 아니다.** -- 재시도는 같은 `Agent` 재호출이며 `SendMessage` 독촉이 아니다. 횟수는 `_progress.md`의 `시도` 칸이 진실원. -- **analyst 2회 실패는 중단**(매핑표 부재 = 기준 부재). producer/qa 실패는 해당 문서만 건너뛰고 누락 명시. - -## 테스트 시나리오 - -정상 흐름 1건(타사 xlsx 시트 10개 → 6단계 슬롯 매핑) + 에러 흐름 1건(원본 쓰기 잠김 → 부분 성공 보고) -→ [references/test-scenarios.md](references/test-scenarios.md) - -## 후속 작업 - -- "OO만 다시" → 해당 에이전트만 재호출하고 이전 `docs/[Ubisam산출물]/_workspace/` 산출물 기반으로 변경분만 갱신 -- 각 에이전트 정의의 `재호출 지침` 섹션이 이전 산출물 처리 방식을 규정한다 -- **연쇄 무효화 확인.** `01_analyst_*`가 갱신되면 그에 의존한 `02_producer_*`·산출물·`03_qa_*`는 - 단순 "재사용"이 아니라 **정합성 미확인**이다. 함께 재실행할지 사용자에게 묻고, 거절하면 - `이전 실행 결과 재사용 — 매핑표 갱신으로 정합성 미확인(YYYY-MM-DD)`으로 표기한다. -- **stale 표기 의무.** 산출물별로 "이번 실행에서 갱신됨(YYYY-MM-DD)" / "이전 실행 결과 재사용(YYYY-MM-DD)"을 - ① 채팅 보고 ② `_workspace/00_rebuild_summary.md` ③ **산출물 파일 자체** — `.md`는 첫 줄, **xlsx는 첫 시트 배너 아래 셀, pptx는 `history` 슬라이드 최신 행**에 - 같은 문구를 남긴다 — 세 곳에 남긴다 - (PTOP 하네스와 동일 규칙). 파일만 열어보는 사람이 최신 여부를 알 수 있어야 한다. - - -## 성공 기준 - -- [ ] 대상 문서의 모든 시트/슬라이드가 매핑표에 등장 (누락 0) -- [ ] `01_analyst_*` → `02_producer_*` → `03_qa_*`가 전부 존재하거나, 없으면 사유가 요약에 명시됨 -- [ ] qa 판정이 통과/조건부 통과/실패 중 하나로 기록됨 -- [ ] 타설비 잔재가 전수 검색으로 확인됨 -- [ ] 창작(매핑표에 없는 내용) 0건 -- [ ] 매핑표의 `[추론]` 항목이 산출물에서 사실로 승격되지 않음 (`rules.md` #15·#16, qa 검증항목 11) -- [ ] `00_rebuild_summary.md`가 존재하고 누락·미검증 항목이 적혀 있음 -- [ ] 한글이 깨지지 않음 (UTF-8) diff --git a/.claude/skills/ubisam-deliverable-rebuild/references/protocol.md b/.claude/skills/ubisam-deliverable-rebuild/references/protocol.md deleted file mode 100644 index f33f57f..0000000 --- a/.claude/skills/ubisam-deliverable-rebuild/references/protocol.md +++ /dev/null @@ -1,38 +0,0 @@ -# 데이터 전달 · 에러 핸들링 (ubisam-deliverable-rebuild) - -`SKILL.md` 본문에서 분리한 상세 규약이다. 오케스트레이터가 Phase 1~3 실행 중 참조한다. - -## 데이터 전달 프로토콜 - -| 대상 | 방식 | -|---|---| -| 진행 추적 | `docs/[Ubisam산출물]/_workspace/_progress.md` (진실원) + `TaskCreate`/`TaskUpdate`(가용 시 보조) | -| 산출물 전달 | 파일 — `docs/[Ubisam산출물]/_workspace/{phase}_{agent}_{artifact}.{ext}` (예: `01_analyst_sw점검결과.md`) | -| 실시간 조율 | `SendMessage` — `to`(이름) + `summary`(5~10단어, **필수**) + `message`. 문서가 여러 건이면 **같은 이름의 에이전트가 여러 개** 뜬다. 그때는 이름 대신 **에이전트 ID**로 지정하고, ID를 `_progress.md` 행에 기록해 둔다 | -| 결과 수집 | `Agent` 반환값 | - -> 서브에이전트가 오케스트레이터(메인 대화)에 회신할 때는 `to: "main"` 이며, -> 이는 **백그라운드로 기동된 서브에이전트만** 쓸 수 있다. - -## 에러 핸들링 - -재시도 횟수는 **`docs/[Ubisam산출물]/_workspace/_progress.md`의 `시도` 칸**에 기록한다(없으면 0회). -저장소 루트의 `_workspace/`(PTOP 하네스)와 **다른 곳이다** — 베어 경로로 쓰지 않는다. -`TaskUpdate`가 가용하면 병행 기록해도 되나 판정 근거는 파일이다. - -**실패 판정 기준(관측 가능해야 한다):** ① 에이전트가 에러로 종료 ② 지정 산출 파일이 생성되지 않음 -③ 산출 파일이 비었거나 헤더만 있음 — 셋 중 하나면 실패로 본다. **지연은 실패가 아니다.** -재시도는 같은 `Agent` 호출을 다시 하는 것을 뜻한다(`SendMessage`로 독촉하는 것이 아니다). - -| 상황 | 처리 | -|---|---| -| **analyst** 실패 (2회) | 매핑표가 없으면 재생산 기준이 없다 → **하네스를 중단**한다. 중단 **전에** `00_rebuild_summary.md`를 "중단 — analyst 2회 실패" 1섹션만으로 먼저 작성해 흔적을 파일에 남기고, 사용자에게 보고한다. 이 경우만 "진행" 규칙의 예외다 | -| **producer/qa** 실패 | 1회 재시도. 재실패 시 해당 문서만 건너뛰고 나머지를 계속 진행, **보고서에 누락을 명시** | -| **산출물** 파일 잠금 | 작업 사본으로 진행, "산출물 미갱신" 표시 후 사용자에게 파일 닫기 요청. (입력 원본은 읽기 전용이므로 애초에 쓰지 않는다) | -| 에이전트 타입 미등록 | Phase 0 가드에서 중단 → "세션 재시작 필요" 보고 | -| 슬롯 전용 xlsx 스크립트 부재 | producer가 `xlsxfill.py` 기반으로 신규 작성 (`ubisam-producer.md` 참조). 수작업 셀 편집은 금지 | -| 데이터 상충 | 삭제하지 않고 출처를 병기 | -| 결함 2회 재작업 후 잔존 | "미해결" 확정, 사용자 판단 항목으로 상신 | - -> 표의 행을 늘리거나 줄이면 `SKILL.md` 본문의 요약 3줄도 **같은 편집에서** 확인한다 -> (`docs/harness-ptop.md` §소비처 확인 의무). diff --git a/.claude/skills/ubisam-deliverable-rebuild/references/test-scenarios.md b/.claude/skills/ubisam-deliverable-rebuild/references/test-scenarios.md deleted file mode 100644 index 4c2d82c..0000000 --- a/.claude/skills/ubisam-deliverable-rebuild/references/test-scenarios.md +++ /dev/null @@ -1,37 +0,0 @@ -# 테스트 시나리오 — `ubisam-deliverable-rebuild` - -정상 흐름 1건 + 에러 흐름 1건. 하네스를 고친 뒤 이 두 경로를 따라가 완주 여부를 확인한다. - -## 정상 흐름 — 타사 xlsx 재생산 - -대상: `Doc/산출물문서/23. SW 점검 결과_PTOP_UBISAM_260616_….xlsx` - -1. **analyst** 가 `openpyxl` 로 시트 10개를 읽어 문서 전체의 **주(主) 단계를 1줄로 선언**하고, - 시트별로 근거와 함께 슬롯에 매핑한다: - - | 시트 | 배치 슬롯 | - |---|---| - | FlowChart · Device · Sequence · IO List · Motor List | 2.설계 | - | Overall | 3.제작 | - | Pos Teaching | 4.셋업 (티칭 좌표는 HW 점검 슬롯) | - | SW Version | 5.양산 | - | Gantt | 01.분석협의·마스터플랜 (일정 산출물) | - | `[작업일지]` | 작업일지 | - - → **10/10 배치, 누락 0.** 동시에 타설비 잔재를 식별한다. -2. **producer** 가 Ubisam 양식 시트로 재배치하고 값마다 출처 주석을 기입한다. -3. **qa** 가 enum · 슬롯 · 잔재 · 출처를 전수 대조 → Critical 0건 → 통과 보고. - -> 검증 통과 기준은 "시트 수가 맞다"가 아니라 **매핑표 ↔ 산출물 ↔ 원본 3자 대조**다. -> 검색으로 0건이 나오면 결함 없음이 아니라 검색식·`.gitignore` 를 먼저 의심한다 -> (`ubisam-qa.md` 작업 원칙 5 참조). - -## 에러 흐름 — 대상 xlsx가 Excel에서 열려 쓰기 잠김 - -1. **producer** 가 잠금을 감지하고 작업 사본으로 생성한 뒤 **"원본 미반영"** 을 로그에 남긴다. -2. **qa** 가 원본 미반영을 **Major** 로 표기한다 — 산출물은 만들어졌으나 반영되지 않았으므로 - 침묵하면 통과로 오해된다. -3. 사용자에게 **"원본을 닫고 재실행해야 함"** 을 명시해 보고한다. - -> 이 흐름의 핵심은 "실패했다"가 아니라 **부분 성공을 부분 성공으로 보고하는 것**이다. -> `00_rebuild_summary.md` 의 누락·미검증 절이 그 종착지다. diff --git a/.claude/skills/ubisam-deliverable/SKILL.md b/.claude/skills/ubisam-deliverable/SKILL.md deleted file mode 100644 index 1540d5d..0000000 --- a/.claude/skills/ubisam-deliverable/SKILL.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -name: ubisam-deliverable -description: Ubisam 산출물 재생산 하네스의 오케스트레이터. 타사 양식 산출물(Doc/산출물문서의 xlsx·pptx)을 Ubisam 협업관리 양식(상태4·유형9·6단계 슬롯·필드 스키마)으로 분석·재배치·재생산·검증하는 분석가·작성가·검증가 3에이전트 팀을 구동한다. "Ubisam 산출물 만들어/재생산/재배치", "협업관리 양식으로", "산출물 채움", "이 문서 Ubisam 단계로", 그리고 후속 표현("다시 실행", "재실행", "업데이트", "수정", "보완", "OO만 다시", "이전 결과 기반") 시 반드시 이 스킬을 사용할 것. 단순 양식 질문은 ubisam-format-map만으로 답할 수 있다. ---- - -# ubisam-deliverable — Ubisam 산출물 재생산 오케스트레이터 - -타사 양식 산출물을 **Ubisam 양식으로 재생산**하는 3에이전트 팀(생성-검증 파이프라인)을 조율한다. - -- 실행 모드: **에이전트 팀** (분석 → 재생산 ↔ 검증) -- 팀원: `ubisam-analyst`, `ubisam-producer`, `ubisam-qa` (모두 `model: "opus"`) -- 공유 스킬: `ubisam-format-map` (양식 enum·스키마·슬롯 매핑 — 모든 팀원이 먼저 읽음) -- 작업공간: 대상별 `_workspace/`, 최종 산출물은 지정 경로 또는 `docs/[Ubisam산출물]/` 하위 - -## Phase 0: 컨텍스트 확인 -1. 대상 산출물과 작업 디렉토리를 정한다. 기본 작업공간: `docs/[Ubisam산출물]/_workspace/`. -2. 실행 모드 판별: - - `_workspace/` 없음 → **초기 실행**(Phase 1부터) - - `_workspace/` 있음 + 부분 수정 요청 → **부분 재실행**(해당 에이전트만) - - `_workspace/` 있음 + 새 입력 → **새 실행**(기존을 `_workspace_prev/`로 이동) -3. `ubisam-format-map` 스킬을 로드해 양식 기준을 확보한다. - -## Phase 1: 분석 (analyst) -- `ubisam-analyst`에게 대상 문서를 주고 구조 분석·타설비 잔재 식별·6단계 슬롯 매핑을 요청한다. -- 산출: `_workspace/01_analyst_{문서}.md`. - -## Phase 2: 재생산 ↔ 검증 (producer ↔ qa, 점진적) -- `ubisam-producer`가 매핑·채움 항목으로 산출물을 재생산한다(xlsx=openpyxl, pptx=`ubisam-ppt-make`, md). -- 각 문서 완성 직후 `ubisam-qa`가 **점진적으로** 검증(enum·슬롯·스키마·잔재·출처·자동화). -- Critical/Major는 producer가 수정 후 재검증. 통과까지 반복(최대 합리적 횟수, 1회 재시도 원칙). - -## Phase 3: 종합·보고 -- 최종 산출물 경로, qa 통과 여부, 미정/TBD 항목, 출처를 사용자에게 요약 보고한다. -- 중간 산출물(`_workspace/`)은 보존(감사 추적). - -## 데이터 전달 프로토콜 -- 태스크 기반(`TaskCreate`/`TaskUpdate`)으로 진행 추적, 파일 기반(`_workspace/`)으로 산출물 전달, 메시지 기반(`SendMessage`)으로 실시간 조율. -- 파일명: `{phase}_{agent}_{artifact}.{ext}` (예: `01_analyst_sw점검결과.md`). - -## 에러 핸들링 -- 에이전트 실패 시 1회 재시도, 재실패하면 해당 결과 없이 진행하고 보고서에 누락을 명시한다. -- 상충 데이터는 삭제하지 않고 출처를 병기한다. - -## 테스트 시나리오 -- **정상 흐름**: `23. SW 점검 결과` xlsx → analyst가 SW Version/Gantt를 6단계 슬롯(제작/양산 등)에 매핑 → producer가 Ubisam 양식 시트로 재배치 → qa가 enum/스키마 검증 → 통과 보고. -- **에러 흐름**: 대상 파일이 편집기 잠금 → producer가 잠금 경고·작업 사본 진행 → qa가 원본 미반영 표시 → 사용자에게 "원본 닫기 후 반영 필요" 보고. - -## 후속 작업 -- 부분 수정 요청("OO만 다시")은 해당 에이전트만 재호출하고, 이전 `_workspace/` 산출물을 기반으로 변경분만 갱신한다. diff --git a/.claude/skills/ubisam-deliverables/README.md b/.claude/skills/ubisam-deliverables/README.md deleted file mode 100644 index 569bae4..0000000 --- a/.claude/skills/ubisam-deliverables/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# ubisam-deliverables (Claude Code Skill) - -Ubisam 협업관리 구조로 **어떤 프로젝트에서든 동일한 산출물 트리·양식**을 생성·관리하는 스킬. -`ref/` 원본 파일 없이도 동작하도록 양식 골격을 MD에 내장(자기완결). - -## 설치 -대상 프로젝트에 폴더째 복사: -``` -<프로젝트>/.claude/skills/ubisam-deliverables/ -``` -(개인 전역으로 쓰려면 `~/.claude/skills/` 아래에 둬도 됨.) - -## 사용 -- "Ubisam 산출물 구조 만들어줘" / "산출물 트리 스캐폴딩" → 트리 생성(A). -- "이 양식 채워줘"(`docs/[Ubisam산출물]/산출물문서/양식/`에 파일 투입 후) → 양식 채움(B). - -## 구성 -``` -SKILL.md # 인덱스 + 오케스트레이션(0 하네스 / A 스캐폴딩 / B 채움) -references/ - 00-harness.md # 호스트 레포 맞물림·비침습 계약 - 01-tree.md # 목표 트리·배치 규칙 - 02-enums.md # 상태4·유형9·티켓코드 - 03-schema.md # 일감·프로젝트 스키마 - 04-stage-deliverables.md# 6단계↔슬롯 매핑 - 05-form-schemas.md # 설계 양식 시트·컬럼(ref 불필요) - 06-procedure.md # 분석→채움 절차 - 07-fill-mapping.md # 프로젝트 분석→산출물 필드 자동 채움 - 08-design-system.md # 색상 팔레트·배너·뱃지·진행률 HTML 템플릿 - 09-pptx-integration.md # PPTX 생성 — ubisam-ppt-make 연동 절차 - xlsxfill.py # xlsx 스타일 상수 + scratch-build API - build_02설계_xlsx.py # 02.설계 xlsx 4종 생성 (독립 실행) - build_02설계_pptx.py # 02.설계 SW_설계서.pptx 생성 (독립 실행) -templates/ - _task.template.md # 일감 카드 템플릿 - project.yaml.template # 프로젝트 메타 템플릿 -``` - -## 원칙 -- 모든 MD 200줄 이내 (`rules.md` #4), 상호 링크로 매핑. -- enum 고정(상태/유형) · 출처 명시 · 조건부 서식 보존 · 레포 루트 보호. diff --git a/.claude/skills/ubisam-deliverables/SKILL.md b/.claude/skills/ubisam-deliverables/SKILL.md deleted file mode 100644 index 9f2a96b..0000000 --- a/.claude/skills/ubisam-deliverables/SKILL.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -name: ubisam-deliverables -description: >- - Ubisam 협업관리(칸반) 구조에 맞춰 프로젝트 산출물을 docs/[Ubisam산출물]/ 트리로 - 구성·관리한다. "산출물 구조 만들기", "Ubisam 양식으로 채우기", "설계/셋업/양산 산출물 - 정리", "산출물 트리 스캐폴딩" 같은 요청에 사용. 6단계(분석·설계·제작·셋업·양산·CS) - 폴더·_meta enum·일감 카드·LGPRI 양식 채움 절차를 제공. - 구분 — 이미 있는 타사 문서를 Ubisam 양식으로 재생산하는 것은 `ubisam-deliverable-rebuild`, - PTOP 소스코드를 읽어 설계 MD를 뽑는 것은 `ptop-deliverables`, enum 조회만이면 `ubisam-format-map`, - **PTOP 아키텍처·구현·빌드 분석**은 `orchestrate-ptop-harness`. - 맨손 "업데이트"·"다시 실행"만으로는 이 스킬을 고르지 않는다 — 무엇을 만들지 먼저 확인한다. ---- - -# Ubisam 산출물 관리 SKILL - -UBISAM 협업관리는 *프로젝트(칸반 보드 1개) → 일감(6단계) → 단계별 산출물* 로 운영된다. -이 스킬은 그 구조를 **소스 레포의 `docs/[Ubisam산출물]/` 하위 파일 트리로 미러링**하고, -LGPRI 제공 양식을 프로젝트 내용으로 채워 관리한다. - -## 언제 쓰나 -- 새 프로젝트에 산출물 트리를 깔 때(스캐폴딩). -- `docs/[Ubisam산출물]/산출물문서/양식/`에 들어온 빈 양식을 프로젝트 내용으로 채울 때. - (입력 원본은 저장소 루트 `Doc/산출물문서/` — 읽기 전용이며 이 스킬이 만들지 않는다) -- 단계별 일감 상태/진행률을 갱신할 때. - -## 참조 맵 (모두 200줄 이내, 필요한 것만 읽기) -| # | 파일 | 용도 | -|---|---|---| -| 0 | [references/00-harness.md](references/00-harness.md) | **하네스**: 호스트 레포 맞물림·비침습 계약 (먼저 읽기) | -| 1 | [references/01-tree.md](references/01-tree.md) | 목표 트리·배치 규칙·우선순위 | -| 2 | [references/02-enums.md](references/02-enums.md) | 상태 4종·유형 9종·티켓코드 규칙 | -| 3 | [references/03-schema.md](references/03-schema.md) | 일감 필드·프로젝트 메타 스키마 | -| 4 | [references/04-stage-deliverables.md](references/04-stage-deliverables.md) | 6단계↔산출물 슬롯 매핑 | -| 5 | [references/05-form-schemas.md](references/05-form-schemas.md) | 설계 양식 시트·컬럼 스키마 | -| 6 | [references/06-procedure.md](references/06-procedure.md) | 분석→채움 절차·조건서식 보존 | -| 7 | [references/07-fill-mapping.md](references/07-fill-mapping.md) | 프로젝트 분석→산출물 필드 자동 채움 매핑 | -| **8** | [**references/08-design-system.md**](references/08-design-system.md) | **색상 팔레트·배너·뱃지·진행률 HTML 템플릿** | -| **9** | [**references/09-pptx-integration.md**](references/09-pptx-integration.md) | **PPTX 생성 — ubisam-ppt-make 연동 절차·슬라이드 매핑** | -| T | [templates/](templates/) | `_task` 카드·`project.yaml` 템플릿 | - -## 진입 가드 (먼저 확인) - -발화에 **무엇을 원하는지**가 없으면(예: "산출물 업데이트해줘"·"다시 실행해줘"·"보완해줘") 스캐폴딩을 바로 깔지 말고 되묻는다. -이 스킬은 폴더·`_task.md`·`README.md`를 수십 개 만들므로, 오발동 시 되돌리는 비용이 크다. - -되물을 것: "① 트리를 새로 깔까요, ② 소스 기준으로 설계 MD를 뽑을까요(`ptop-deliverables`), -③ 기존 문서를 Ubisam 양식으로 재생산할까요(`ubisam-deliverable-rebuild`)?" - -생성할 폴더·파일 목록을 제시하고 승인을 받은 뒤 A단계를 시작한다 (`rules.md` #2). - -## 실행 순서 (오케스트레이션) - -### 0. 하네스 진입 (항상 먼저) -[00-harness.md](references/00-harness.md)의 비침습 계약 확인 → 호스트 `CLAUDE.md`·소스에서 프로젝트 사실 읽기 → `project_code`/`project_name` 자동 추정(실패 시 질문). - -### A. 스캐폴딩 (트리 생성) -0. **생성할 폴더·파일 목록을 사용자에게 제시하고 승인을 받는다** (`rules.md` #2). - 이 단계는 수십 개 파일을 만들므로 되돌리는 비용이 크다. -1. 소스 레포 루트의 `.claude/`·`CLAUDE.md`·`rules.md`는 **건드리지 않는다**. -2. `docs/[Ubisam산출물]/` 아래에 [01-tree.md](references/01-tree.md)의 트리를 생성: - - `_meta/`(enum·스키마) ← [02](references/02-enums.md)·[03](references/03-schema.md) 내용으로 채움. - - `01.분석협의 ~ 06.CS/` 6단계 폴더 + 각 `_task.md`(템플릿: [templates/_task.template.md](templates/_task.template.md)). - - 각 단계 산출물 슬롯 하위폴더 + `.gitkeep` ← [04](references/04-stage-deliverables.md). - - `docs/[Ubisam산출물]/산출물문서/`(+`양식/` 드롭존), `ref/`, `[분석]/`, `[작업일지]/`. - > **저장소 루트 `Doc/산출물문서/`와 다른 곳이다.** 전자는 스캐폴딩이 만드는 트리 내부, - > 후자는 **입력 원본 드롭존**(스캐폴딩 대상이 아니며 읽기 전용). -3. `RULES.MD`(산출물 영역 규칙) + `README.md`(트리 한눈에 + 단계별 현황 뱃지 표)를 루트에 작성. -4. `_meta/project.yaml`의 `{...}` 토큰은 프로젝트 정보로 교체. 모르면 그대로 두고 사용자에게 질문. -5. **디자인 적용**: [08-design-system.md](references/08-design-system.md) — - `_task.md`는 **§7 완성 템플릿**을 그대로 적용하고, `README.md`는 **§7 템플릿이 없으므로** - §1 배너 + §2·§3 뱃지 + §4 진행률 바를 조합해 단계별 현황 표를 만든다. - -### B. 양식 채움 (산출물 생성) -[06-procedure.md](references/06-procedure.md) 절차를 따른다: 분석 → 타설비 잔재 식별 → 프로젝트 내용 채움(출처 명시) → 슬롯 배치 → `_task.md` 진행률 갱신 → `[작업일지]` 기록. -- **자동 채움**: 호스트 분석 사실을 [07-fill-mapping.md](references/07-fill-mapping.md) 매핑으로 산출물 필드에 기입. -- **디자인 적용**: 생성하는 모든 MD에 [08-design-system.md](references/08-design-system.md) 배너·뱃지·섹션헤더 삽입. -- 양식의 시트·컬럼 골격은 [05-form-schemas.md](references/05-form-schemas.md) 참조(ref 불필요). -- 상태/유형 값은 [02-enums.md](references/02-enums.md) enum만 사용(임의 신규값 금지). - -### C. PPTX 생성 — ubisam-ppt-make 스킬에 위임 (직접 생성 금지) -> **이 스킬은 PPTX를 직접 생성하지 않는다.** -> PPTX 렌더링은 반드시 `ubisam-ppt-make` 스킬의 `build_deck.py`를 통해서만 수행한다. -> 이 스킬의 역할은 ① 슬라이드 spec JSON 준비 ② `build_deck.py` 호출 ③ 결과 슬롯 배치. - -상세 절차 → [09-pptx-integration.md](references/09-pptx-integration.md) - -- **2.설계 완료** → `SW_설계서.pptx`: `PYTHONUTF8=1 py .claude/skills/ubisam-deliverables/references/build_02설계_pptx.py` -- **5.양산 완료 or 명시 요청** → `<설비명>_HMI_매뉴얼.pptx`: MD → spec JSON → `ubisam-ppt-make/build_deck.py` -- 레이아웃·디자인 토큰은 **ubisam-ppt-make/SKILL.md 기준**. 이 스킬에서 재정의 금지. - -## 불변 규칙 (항상 지킴) -- **MD 200줄 상한** (`rules.md` #4): 새 문서가 길어지면 분할하고 상호 링크(`[[...]]`/상대경로)로 매핑. -- **enum 고정**: 상태·유형은 회사 공통 마스터. 새 값 발견 시 `_meta/*.enum.md` 먼저 갱신. -- **출처 명시**: 채운 내용은 원본 파일·코드 경로를 문서에 남긴다. -- **추론 표기**: 원본을 확인하지 않고 판단으로 채운 값·해석은 문장 앞에 `[추론]` (`rules.md` #15·#16). - 자동 채움 단계가 게이트 없이 값을 만들 수 있는 유일한 경로이므로 여기서 표기가 빠지면 이후 검증가가 잡을 근거가 없다. - 확인 후에는 표기를 떼고 출처로 바꾼다. 검색은 **`\[추론\]`** 로 이스케이프한다(대괄호=문자클래스). -- **디자인 의무**: 생성하는 모든 산출물 MD에 [08-design-system.md](references/08-design-system.md) 배너·뱃지 적용. 텍스트 단독 표기 금지. -- **xlsx 재생산** (**`ptop-deliverables` 경로 한정** — rebuild 경로는 `xlsxfill` 기반 신규 스크립트): - `references/build_02설계_xlsx.py` + `xlsxfill.py`로 완전 독립 생성(ref 불필요). 스타일 상수는 xlsxfill.py에 하드코딩. 저장소 루트에서 `PYTHONUTF8=1 py .claude/skills/ubisam-deliverables/references/build_02설계_xlsx.py` 한 줄 실행 (`cd` 금지 — 출력 경로가 어긋난다). -- **pptx 재생산**: `references/build_02설계_pptx.py`로 완전 독립 생성(ref 불필요). 슬라이드 스펙 내장, `build_deck.py` 자동 호출. `PYTHONUTF8=1 py .claude/skills/ubisam-deliverables/references/build_02설계_pptx.py` 한 줄 실행. - 이 스크립트는 `__file__` 기준 절대경로를 쓰므로 cwd와 무관하다 (xlsx 쪽은 상대경로라 반드시 저장소 루트에서 실행). -- **루트 보호**: 레포 루트 `rules.md` > 본 산출물 `RULES.MD`(스코프 하위). - -> 단독 호출로 마무리할 때: 보고는 `rules.md` #11~13 출력 형식(수정 줄=초록 화살표, 단어=주황, 미변경=기본색)을 -> 따르고, 끝에 관련 `.md`를 갱신할 부분이 있는지 묻는다(`rules.md` #6). diff --git a/.claude/skills/ubisam-deliverables/references/00-harness.md b/.claude/skills/ubisam-deliverables/references/00-harness.md deleted file mode 100644 index ca2c9a7..0000000 --- a/.claude/skills/ubisam-deliverables/references/00-harness.md +++ /dev/null @@ -1,68 +0,0 @@ -# 00 · 하네스 (호스트 프로젝트 맞물림 설계) - -> 이 스킬이 **이미 CLAUDE.md·.claude가 있는 임의의 소스 레포**에 들어가 기존 에이전트와 -> 충돌 없이 맞물려 동작하기 위한 계약. SKILL.md가 가장 먼저 참조한다. - -## 비침습 계약 (절대 규칙) -- **읽기만**: 호스트의 `CLAUDE.md`, `.claude/`, `RULES.md`, `src/`·소스코드는 입력으로만 읽는다. -- **쓰기 격리**: 모든 생성/수정은 `docs/[Ubisam산출물]/` 하위로 한정. -- **경로 인용 의무 — 수단마다 방법이 다르다.** 이 경로의 대괄호는 문자클래스로 해석된다. - **틀리면 에러가 아니라 조용히 0건**이 나오므로 검증이 통째로 헛돈다. (실측 확인) - - | 수단 | 올바른 방법 | - |---|---| - | 셸(bash) | 따옴표로 감싼다 — `"docs/[Ubisam산출물]/…"` | - | `Glob` 도구의 `pattern` | **백슬래시 이스케이프** — `docs/\[Ubisam산출물\]/**/*.xlsx` (따옴표는 무효) | - | `Grep` 도구의 `glob` | 동일하게 이스케이프하거나, 아래처럼 `path`로 분리 | - | `Grep`/`Glob`의 `path` | **리터럴로 취급되므로 그대로** 쓴다 — `path: "docs/[Ubisam산출물]"` + `pattern: "**/*"` | - | Python `os.path` | 무관 (그대로) | -- **임시 파일**: `py`는 네이티브 Windows 바이너리다. Git Bash(MSYS)가 POSIX 절대경로를 Windows - 경로로 **자동 변환**하므로 대개 동작하지만(실측 확인), 변환이 암묵적이라 파일이 어디에 떨어졌는지 - 추적하기 어렵다. 임시 파일은 **저장소 상대경로**(`docs/[Ubisam산출물]/_workspace/`)에 만들어 - 위치를 확정한다. -- **우선순위**: 호스트 루트 `rules.md`/`CLAUDE.md` > 본 산출물 규칙. 충돌 시 호스트 우선. -- **멱등**: 폴더·`.gitkeep`·`_task.md`는 "없으면 생성, 있으면 유지". - **산출물 파일(xlsx·pptx·md)은 재생산 스크립트가 덮어쓴다** — 스크립트가 진실원이므로 매번 같은 결과가 나온다. - 손으로 편집한 산출물은 다음 재생산에서 사라지므로, 내용 변경은 스크립트·매핑표 쪽을 고친다. - -## 입력 (호스트에서 읽는 진실원) -| 입력 | 용도 | -|---|---| -| 루트 `CLAUDE.md` | 설비·플랫폼·디바이스·시퀀스 등 프로젝트 사실 | -| 소스코드(`src/`,`Machines/` 등) | PLC/모션/IO/Vision 구성, 메인 시퀀스 추출 | -| `README*`, 설계 문서 | 보조 컨텍스트 | -| git 원격/폴더명 | 프로젝트 코드·명 자동 추정 | - -추출 사실 → 산출물 필드 매핑은 [07-fill-mapping.md](07-fill-mapping.md). - -## 데이터 흐름 (호스트 에이전트와 맞물림) -``` -[호스트 CLAUDE.md + 소스] ──읽기──▶ (분석) ──▶ 사실 추출 - │ │ - ▼ ▼ - docs/[Ubisam산출물]/ 트리 생성 ◀── 매핑(07) ── 산출물 필드 채움 - │ - ▼ - _task.md 진행률 갱신 + [작업일지] 기록 -``` -- 스킬은 **온디맨드** 호출(트리거 문구). 호스트 에이전트 루프를 가로채지 않는다. -- 분석/검색은 호스트 에이전트의 도구(Grep/Read)를 그대로 활용. - -## 프로젝트 자동 인식 -1. `project_code`: git 원격명·폴더명·`CLAUDE.md`에서 추정 → 실패 시 사용자에게 질문. -2. `project_name`: `CLAUDE.md` 제목/설비명에서 추정. -3. 추정값은 `_meta/project.yaml`에 기록하고 **`[추론]`** 표기 (`rules.md` #15·#16 — 구 `(추정)` 대체). - 확정 전까지 문서에 `(제안)` 유지. 두 표기는 축이 다르다 — `[추론]`=확인 전 서술, `(제안)`=진실원 부재. - -## 트리거 문구 -- 생성: "산출물 구조 만들어줘", "Ubisam 트리 스캐폴딩". -- 채움: "설계 산출물 채워줘", "IO 맵 정의서 생성", "프로젝트 분석해서 산출물 채움". -- 갱신: "2.설계 진행률 갱신", "양산 단계 산출물 추가". - -## 안전장치 -- 호스트 파일 수정 요청이 들어오면 거부하고 `docs/` 내 대안 제시. -- 양식 엑셀은 **ref 파일 없이 from-scratch로 생성**한다([05-form-schemas.md](05-form-schemas.md)·[06-procedure.md](06-procedure.md)). - **스타일 상수**(색·폰트·테두리)는 `xlsxfill.py`에 내장돼 있다. (원본 템플릿 복제 방식은 폐기됨 — ref 파일에 의존하지 않기 위함) - ⚠ **조건부서식은 `xlsxfill.py`에 없다**(관련 API 0건). 필요하면 `openpyxl.formatting`을 직접 쓰되 - 색·폰트는 `xlsxfill` 상수를 쓰고, 재현 불가하면 지어내지 말고 **"조건부서식 미이관"** 을 로그에 명시한다 - (`ubisam-producer.md` §에러 핸들링과 같은 규칙). diff --git a/.claude/skills/ubisam-deliverables/references/01-tree.md b/.claude/skills/ubisam-deliverables/references/01-tree.md deleted file mode 100644 index 8d5e9a2..0000000 --- a/.claude/skills/ubisam-deliverables/references/01-tree.md +++ /dev/null @@ -1,44 +0,0 @@ -# 01 · 목표 트리 & 배치 규칙 - -> 이 스킬만으로(ref 없이) 어떤 프로젝트에서도 동일 트리를 생성한다. - -## 배치 원칙 -- 산출물은 **소스 루트가 아니라 `docs/[Ubisam산출물]/` 하위**에 둔다. -- 루트의 `.claude/`·`CLAUDE.md`·`rules.md`는 손대지 않는다. -- 우선순위: 레포 루트 `rules.md` > 본 산출물 `RULES.MD`(스코프 하위). - -## 트리 - -``` -<소스레포루트>/ -├─ .claude/ CLAUDE.md RULES.md # (기존) 손대지 않음 -└─ docs/ - └─ [Ubisam산출물]/ - ├─ RULES.MD # 산출물 영역 규칙(이 스킬이 생성) - ├─ README.md # 트리 한눈에 + 시작하기 - ├─ _workspace/ # 하네스 중간 산출물(_progress.md, 01_analyst~03_qa) - ├─ _meta/ - │ ├─ project.yaml # → templates/project.yaml.template - │ ├─ status.enum.md # → 02-enums §상태 - │ ├─ task-type.enum.md # → 02-enums §유형 - │ ├─ task-schema.md # → 03-schema §일감 - │ ├─ ticket-code.rule.md # → 02-enums §티켓코드 - │ └─ build_scripts/ # producer가 만든 슬롯별 xlsx 빌더 (xlsxfill 임포트) - ├─ 01.분석협의/ _task.md + 사양서/ 회의록_CR/ 마스터플랜/ - ├─ 02.설계/ _task.md + UIUX_기능설계/ 시퀀스_인터록/ IO_DB설계/ 설계리뷰_DR/ - ├─ 03.제작/ _task.md + 테스트결과_CheckList/ - ├─ 04.셋업/ _task.md + HW_IO모션점검/ 파라미터_레시피백업/ 이슈로그_IssueLog/ SAT_인수검사보고서/ - ├─ 05.양산/ _task.md + 운영매뉴얼_HMI/ 최종SW_마스터백업/ 프로젝트완료보고서/ - ├─ 06.CS/ _task.md - ├─ 산출물문서/ README.md + 양식/(빈 양식 드롭존) - │ ※ 저장소 루트 `Doc/산출물문서/`(입력 원본, 읽기 전용)와 다른 곳 - ├─ ref/ # 참고자료(읽기전용) — 비어 있어도 무방 - ├─ [분석]/ # 에이전트 분석 산출물(날짜_주제.md) - └─ [작업일지]/ # 일자별 로그(yyyy_mm_dd.md) -``` - -산출물 슬롯 폴더는 비어 있으면 `.gitkeep`을 둔다. 슬롯 상세 매핑은 [04-stage-deliverables.md](04-stage-deliverables.md). - -## 폴더명 규칙 -- 단계: `NN.단계명`(2자리 zero-pad). 협업관리 일감 제목과 동일 어휘. -- 산출물 슬롯: 한글_영문 혼합 가능, 공백 대신 `_`. diff --git a/.claude/skills/ubisam-deliverables/references/02-enums.md b/.claude/skills/ubisam-deliverables/references/02-enums.md deleted file mode 100644 index 4e9d5f0..0000000 --- a/.claude/skills/ubisam-deliverables/references/02-enums.md +++ /dev/null @@ -1,59 +0,0 @@ -# 02 · enum & 티켓코드 (회사 공통 마스터) - -> 임의 신규값 금지. 새 값 발견 시 이 파일을 먼저 갱신 후 사용. -> 스캐폴딩 시 §상태→`status.enum.md`, §유형→`task-type.enum.md`, §티켓코드→`ticket-code.rule.md`로 복사. - -## §상태(Status) — 4종 (전이 순서) - -``` -해야 할 일 → 분석 진행 → 업무 진행중 → 진행 완료 -``` - -아래 **HEX는 MD·HTML 뱃지용**이다. xlsx 셀 채우기 ARGB는 `ubisam-format-map` §1을 쓴다. - -| 코드(한글) | 색 | HEX | 칸반 컬럼 | -|---|---|---|---| -| 해야 할 일 | 회색 | `#757575` | Todo | -| 분석 진행 | 청색 | `#1976D2` | Select For dev | -| 업무 진행중 | 파랑 | `#1565C0` | InProgress | -| 진행 완료 | 연두 | `#689F38` | Done | - -컬럼 옵션: "상태 없으면 게시판 비표시", "WIP 초과 강조". - -## §유형(Type) — 9종 - -| 유형 | 색 | HEX | 6단계 매핑(관례) | -|---|---|---|---| -| 오류수정 | 빨강 | `#D32F2F` | — | -| 불합리 | 주황 | `#F57C00` | — | -| 미팅 | 청록 | `#00796B` | 1.분석/협의 | -| 설계 | 연두 | `#689F38` | 2.설계 | -| 개발 | 파랑 | `#1976D2` | — | -| 제작 | 남파랑 | `#283593` | 3.제작 | -| 입고셋업 | 보라 | `#7B1FA2` | 4.셋업 | -| 적용 및 모니터링 | 하늘 | `#0288D1` | 5.양산 | -| 요청대응 | 남색 | `#1A237E` | 6.CS | - -> 뱃지 HTML 템플릿은 [08-design-system.md](08-design-system.md) § 2·3 참조. - -## §우선순위 -- 확인값: `보통`(Normal). 그 외 등급 미확인 — 발견 시 보강. - -## §티켓코드 규칙 - -``` -{프로젝트코드}-{일련번호} -``` -- 프로젝트코드: `_meta/project.yaml › project_code` 에서 읽는다. **여기에 특정 프로젝트 값을 적지 않는다** - (`ubisam-format-map` §5 — 하네스가 잡아야 할 타설비 잔재를 스스로 공급하게 된다). -- 일련번호: 4자리 권장, 생성 순 증가. -- 전체 형식: `{project_code}-{NNNN}` - -| 일감 | 일련번호 | -|---|---| -| 1.분석/협의 | `{N}` | -| 2.설계 | `{N+1}` | -| 3.제작 | `{N+2}` | -| 4.셋업 | `{N+3}` | -| 5.양산 | `{N+4}` | -| 6.CS | `{N+5}` | diff --git a/.claude/skills/ubisam-deliverables/references/03-schema.md b/.claude/skills/ubisam-deliverables/references/03-schema.md deleted file mode 100644 index 66a1b3c..0000000 --- a/.claude/skills/ubisam-deliverables/references/03-schema.md +++ /dev/null @@ -1,39 +0,0 @@ -# 03 · 일감 & 프로젝트 스키마 - -> 스캐폴딩 시 §일감→`task-schema.md`, 프로젝트 메타→`project.yaml`(템플릿 사용). - -## §일감(Task) 필드 - -| 필드 | 비고 | -|---|---| -| 제목 | `N.단계명` (예: `2.설계`) | -| 티켓번호 | `{프로젝트코드}-{일련번호}` → [02-enums §티켓코드](02-enums.md) | -| 유형 | [02-enums §유형](02-enums.md) (9종) | -| 상태 | [02-enums §상태](02-enums.md) (4종) | -| 우선순위 | `보통` 등 | -| 담당자 / 참조자 | 이름(직급) 표기 (예: 홍길동(사원)) | -| 진행률 | % | -| Hashtag | 자유 태그 (예: 분석/검토/협의) | -| 등록일 / 수정일 / 종료일 | `yyyy/mm/dd` | -| 예상시간 | `2w 4d 6h 45m` 형식 | -| 수정 버전 | None 가능 | -| 첨부파일 | 최대 2.93GB | -| 체크리스트 | 의견글 / 시간변경이력 / 타임 트래킹 | - -`_task.md` 카드 양식은 [templates/_task.template.md](../templates/_task.template.md). - -## §프로젝트 메타 - -| 필드 | 예시/형식 | -|---|---| -| 프로젝트명 | `{사업부}_{고객사}_{설비명} 운영SW` | -| 종류 | Software / Hardware | -| 프로젝트 형식 | Kanban | -| 코드명 | `{CUST}_{TYPE}_{NN}_{YYYYMMDD}` | -| 사업부 / 팀 | `{사업부}` / `{팀}` | -| PL / 등록자 | `{이름}({직급})` | -| 계약일 / 납기 | `yyyy-mm-dd` | -| 권한 | 책임자 → 참여자 → 열람자 (3단계) | -| 알람 | 실시간 티켓 / 메일 / 댓글 | - -전체 템플릿(토큰 포함): [templates/project.yaml.template](../templates/project.yaml.template). diff --git a/.claude/skills/ubisam-deliverables/references/04-stage-deliverables.md b/.claude/skills/ubisam-deliverables/references/04-stage-deliverables.md deleted file mode 100644 index cefe138..0000000 --- a/.claude/skills/ubisam-deliverables/references/04-stage-deliverables.md +++ /dev/null @@ -1,39 +0,0 @@ -# 04 · 6단계 ↔ 산출물 슬롯 매핑 - -> 각 단계 폴더 = 협업관리 일감 1개. 슬롯 = 산출물 보관 하위폴더. 비면 `.gitkeep`. - -| # | 폴더 | 유형 | 슬롯(하위폴더) | 산출물 | -|---|---|---|---|---| -| 1 | `01.분석협의/` | 미팅 | `사양서/` `회의록_CR/` `마스터플랜/` | 사양서(URS)·CR회의록·마스터플랜 | -| 2 | `02.설계/` | 설계 | `UIUX_기능설계/` `시퀀스_인터록/` `IO_DB설계/` `설계리뷰_DR/` | 기능명세서·시퀀스/인터록·통신/IO맵·DB스키마·D/R회의록 | -| 3 | `03.제작/` | 제작 | `테스트결과_CheckList/` | 단위/통합 테스트 결과 보고서 | -| 4 | `04.셋업/` | 입고셋업 | `HW_IO모션점검/` `파라미터_레시피백업/` `이슈로그_IssueLog/` `SAT_인수검사보고서/` | IO/모션 점검·파라미터/레시피 백업·이슈로그·SAT 결과서 | -| 5 | `05.양산/` | 적용 및 모니터링 | `운영매뉴얼_HMI/` `최종SW_마스터백업/` `프로젝트완료보고서/` | 운영매뉴얼(HMI/알람)·최종SW 백업·완료 보고서 / **`*.pptx`** (ubisam-ppt-make Step C) | -| 6 | `06.CS/` | 요청대응 | (슬롯 없음, 건별 누적) | CS 대응 이력 | - -## 단계별 세부 산출물 정의(채움 기준) - -### 1.분석/협의 -- 요구사항 분석: 고객 사양서(URS) 분석 / 제어 시나리오 검토 → CR회의록 / 마스터플랜. - -### 2.설계 -- UI/UX·기능: HMI 화면 정의서·UI 스토리보드·기능 명세서. -- 시퀀스·인터록: 제어 시퀀스 다이어그램 & 인터록 정의서. -- I/O·DB: 통신 맵(Memory/IO/Register)·DB 스키마 정의서. -- 설계 리뷰: D/R 회의록. -- 양식 시트 골격 → [05-form-schemas.md](05-form-schemas.md). - -### 3.제작 -- 개발 환경 구축 / 핵심 모듈 / UI·메인 시퀀스 / 시뮬레이션 검증 / 단위·통합 테스트(Check-List). - -### 4.셋업 -- HW IO/모션 점검 시트 · 파라미터/레시피 백업 · 이슈 로그(Issue Log) · 호스트(MES) 연동 · SAT 결과서. - -### 5.양산 -- Ramp-up 교육 · 안정화 모니터링(운영 매뉴얼·알람 조치서) · S/W 최적화 · 최종 버전 동결(마스터 백업) · 프로젝트 완료 보고서. - -### 6.CS -- 운영 단계 요청 대응 이력(요청/조치/결과) 누적. - -## 타사 산출물 이관 가이드(예) -- 제작사양서·시퀀스 → `01`, IO/PLC 인터페이스·기능명세서·FlowChart → `02`, HMI Manual·알람조치 → `05`. diff --git a/.claude/skills/ubisam-deliverables/references/05-form-schemas.md b/.claude/skills/ubisam-deliverables/references/05-form-schemas.md deleted file mode 100644 index 4d2054b..0000000 --- a/.claude/skills/ubisam-deliverables/references/05-form-schemas.md +++ /dev/null @@ -1,109 +0,0 @@ -# 05 · 설계 양식 시트·컬럼 스키마 - -> **재생산 방식 (2026-06-29 확정): 완전 독립 (ref 파일 불필요)** -> xlsx는 `xlsxfill.py` 의 하드코딩 스타일 상수와 `build_02설계_xlsx.py` 의 PtoP 데이터만으로 처음부터(`from scratch`) 생성한다. ref 원본 xlsx 없이도 동일한 외형을 재현한다. -> -> **재생산 도구 (영구 보존)** -> - `xlsxfill.py` — 같은 폴더. xlsxfill.py 내장 스타일 상수 + `make_workbook / write_banner / write_header_row / write_data_rows / group_merge` scratch-build API. -> - `build_02설계_xlsx.py` — 같은 폴더. PtoP 데이터 내장, 단독 실행으로 4개 xlsx 재생산. -> ``` -> PYTHONUTF8=1 py .claude/skills/ubisam-deliverables/references/build_02설계_xlsx.py -> ``` -> 저장소 루트에서 한 줄로 실행한다. `PYTHONUTF8`을 별도 줄에 두면 적용되지 않는다. -> -> **⚠ 이 스크립트는 PTOP 소스 유래 재생산(`ptop-deliverables`) 전용이다.** -> 타사 문서를 재생산하는 `ubisam-deliverable-rebuild` 경로에서는 쓰지 않는다 — -> 데이터가 코드에 하드코딩돼 있어 매핑표를 반영할 수 없다(`ubisam-producer.md` §2). -> - 전제조건: Python 3.9+, openpyxl >= 3.1 (`pip install openpyxl`) -> -> **공통 관례**: ① 배너 B2=제목, B3=근거/부제 ② 미확정 값은 `(제안)` 표기 ③ 플랫폼 문구는 `_meta/project.yaml`에서 읽는다 (특정 문구를 여기에 하드코딩하지 않는다) - ---- - -## 스타일 상수 (xlsxfill.py 하드코딩값) - -| 구분 | 폰트 | 색상(fgColor) | 테두리 | -|---|---|---|---| -| 배너 행(B2) | 맑은 고딕 13pt Bold White(FFFFFF) | FF1F4E78 (진네이비) | medium all | -| 부제 행(B3) | 맑은 고딕 9pt | 없음 | medium L/R/T | -| 헤더 행 | 맑은 고딕 11pt Bold White(FFFFFF) | FF2E75B6 (파랑) | medium 좌우, thin 상하 | -| 데이터 행(홀수) | 맑은 고딕 10pt | FFDDEBF7 (연파랑) | medium 좌우, thin 상하 | -| 데이터 행(짝수) | 맑은 고딕 10pt | FFFFFFFF (흰색) | medium 좌우, thin 상하 | -| 기능명세서 배너 | 맑은 고딕 14pt Bold | 없음 | medium all | -| 기능명세서 헤더 | 맑은 고딕 11pt Bold | **없음** | thin all | -| 기능명세서 데이터 | 맑은 고딕 11pt | 없음 | thin all | -| TactTime 헤더 | 맑은 고딕 11pt | **없음** | thin all | -| TactTime 데이터 | 맑은 고딕 11pt | 없음 | thin all | - -> `write_header_row(fill=None)` — 배경 없음(기능명세서·TactTime 계열). 인자 생략 시 파랑(HEADER_FILL) 기본값. `fill=_UNSET` sentinel으로 구분. -> `TODAY = datetime.date.today()` — 실행일 자동 반영. 이력 셀(Update 컬럼)에 삽입. -> **`xlsxfill.py` 가 아니라 `build_02설계_xlsx.py:41` 의 모듈 상수다** — 새 빌드 스크립트를 쓸 때는 -> `xlsxfill` 에서 임포트되지 않으므로 직접 정의해야 한다. - ---- - -## A. 모션축·IO 맵 정의서 (슬롯 `02.설계/IO_DB설계/모션축_IO맵_정의서.xlsx`) -**3탭 고정** - -| 탭명 | 헤더(B4~) | 데이터 시작행 | PtoP 특이사항 | -|---|---|---|---| -| 통신·제어 구성 | 구분\|대상\|컨트롤러/디바이스\|통신/버스\|수량·범위\|비고 | B5 | PLC=MXComponent, IO=**보드타입 런타임 설정(미확정)**, Laser=IOGate, Scanner=RTC | -| 모션축 정의(ACS) | Axis\|축명(논리)\|용도\|컨트롤러/통신\|구동\|행정/범위\|최대속도\|Home방식\|Soft Limit\|동기/단축\|비고 | B5 | X/Y=ACS EtherCAT, Z=AuroraMotionBoard(보드타입 미확정), Scanner θ/XY=RTC. 행정·속도·Home=(제안) | -| I-O 맵(DI-DO) | No\|신호명\|Type\|권장모듈\|슬롯/CH\|Active\|설명/인터락\|비고 | B5 | DI 9~23 / DO 9~17 (`PAIX_PTOP.cs` — 채널 번호만. **벤더명은 이 파일에 없다**) | - -## B. PLC-PC 인터페이스 신호 정의서 (슬롯 `02.설계/IO_DB설계/PLC_PC_인터페이스_신호정의서.xlsx`) -**4탭 고정** - -| 탭명 | 헤더(B4~) | 데이터 시작행 | -|---|---|---| -| 통신 사양 | 항목\|내용 | B5 | -| PC→PLC (Write) | No\|Seq/구분\|신호명\|방향\|디바이스(제안)\|Type\|의미 / 트리거\|응답·완료\|비고 | B5 | -| PLC→PC (Read) | 동일 | B5 | -| 핸드셰이크 시퀀스 | No\|Seq\|Step\|주체\|동작 / 신호\|디바이스(제안)\|비고 | B5 | - -- Seq 구분 enum: Status · Alarm · Process · Request · Info · Control · Model · Interlock -- 디바이스: 비트 `M70000~`(PC Write), `M70500~`(PLC Read). 워드 `D70000~`/`D70500~`. - **⚠ 전부 `(제안)` 값이다** — 이 주소들은 `.cs` 소스에 0건이고 근거는 분석 문서뿐이다 - (`ptop-deliverables/references/source-map.md` §A 참조). 산출물에 확정값처럼 적지 말 것. -- PtoP 핸드셰이크: `PLC_PAGE_CHANGE_REQ` 단일 게이트 → Recipe 확정 → **Page 3회 검증**(200ms×3) → 리스트 업로드 → 발진 → 완료. - 출처: `SeqAutoRunPTOP.cs` `CheckPageNoComp` — `checknum > 2`에서 break하므로 정확히 3회이고 - 각 회차에 `Thread.Sleep(200)`이 있다. `plcPageNoList[0]/[1]/[2]` 로그가 3회를 확증한다. - ⚠ 같은 함수의 `260618` 주석은 "상한 하드코딩(>2) 제거 → Recipe 페이지 수로 가변 검증"이라고 - 적혀 있으나 **코드는 아직 `>2` 고정**이다(`recipePageCount`는 값 범위 검증에만 쓰인다). - 주석을 근거로 "가변"이라 적지 말 것 (`rules.md` #1). - -## C. 기능명세서 / UI 설계 (슬롯 `02.설계/UIUX_기능설계/기능명세서.xlsx`) -**8탭 고정** (우리 설비에 없는 탭도 양식 유지) - -| 탭명 | 헤더(행5~) | G3 배너 | PtoP 내용 | -|---|---|---|---| -| OverView | no.\|Content | — | SW 개요(Aurora·Win11·.NET·설비·모션·레이저·PLC·비전) | -| MainView | Update\|Funtion Area\|Funtion Name\|NO\|Sub\|Content | "다음은 Main 화면…" | AutoRun 시작/정지·페이지·Resume(bit15)·스캐너캔버스 | -| RecipeView | 동일 | "다음은 Recipe 화면…" | ActivateRecipe·변경이력·모델 편집 | -| ManualView | 동일 | "다음은 Manual 화면…" | ScannerOperation·ModelFinder·Calibration | -| DeviceView | 동일 | "다음은 Device 화면…" | DeviceSetting·PLCBit/Word·IOInterface | -| SettingView | 동일 | "다음은 Setting 화면…" | Equipment·Log·AutoBackup·Alarm·Stream | -| VisionView | 동일 | "다음은 Vision 화면…" | `(해당없음)` — AuroraVision 미사용 | -| Sequence 흐름 | Update\|Funtion Area\|Processing Name\|NO\|Content | — | `PLC_PAGE_CHANGE_REQ` 게이트→Recipe→Page→ListUpload→발진→완료→루프백 | - -## D. TactTime 산정서 (슬롯 `02.설계/시퀀스_인터록/TactTime_산정서.xlsx`) -**2탭 고정** - -| 탭명 | 좌측 컬럼 | 우측 컬럼 | PtoP 내용 | -|---|---|---|---| -| PC TactTime | 공정\|Unit\|단위동작\|T/T | Working Process\|상세합계\|기준/참조합계 | SeqAutoRunPTOP.cs 타이밍 (Page gate·Recipe·발진·완료) | -| PLC TactTime | 동일 구조 | — | 미입수 → `(제안)` | - -## E. Flow Chart (슬롯 `02.설계/시퀀스_인터록/`) -- 형식: PPTX 흐름도. 메인 시퀀스: `PLC_PAGE_CHANGE_REQ` 단일게이트 → 리스트 업로드 → 발진 → 완료비트. 분기·인터락 표현. - -## enum 요약(양식 고정값) -- I/O Type: DI · DO · AI · AO -- 신호 Type: BIT · INT · INT32 -- PLC Seq 구분: Status · Alarm · Process · Request · Info · Control · Model · Interlock -- 운영 모드: 수동 · 반자동 · 자동 - -> **재생산 도구 선택은 이 문서 상단의 ⚠ 박스를 따른다.** -> `ptop-deliverables`(소스 유래) 경로에서만 `build_02설계_xlsx.py`를 저장소 루트에서 실행한다. -> `ubisam-deliverable-rebuild`(타사 문서 재생산) 경로에서는 이 스크립트를 쓰지 않고 -> `xlsxfill.py` 기반 신규 스크립트를 작성한다(`ubisam-producer.md` §2). diff --git a/.claude/skills/ubisam-deliverables/references/06-procedure.md b/.claude/skills/ubisam-deliverables/references/06-procedure.md deleted file mode 100644 index 86e036d..0000000 --- a/.claude/skills/ubisam-deliverables/references/06-procedure.md +++ /dev/null @@ -1,46 +0,0 @@ -# 06 · 분석 → 채움 절차 - -> 입력: `docs/[Ubisam산출물]/산출물문서/양식/`(빈 양식) 또는 타설비 산출물. 출력: 단계 슬롯에 채운 산출물 + 갱신된 `_task.md` + 로그. - -## 절차 -1. **분석**: 원본 구조 파악(시트/슬라이드/컬럼). 결과를 `[분석]/_<주제>-분석.md`에 기록. - - 엑셀 구조 추출(파이썬·Office 없이): `unzip -p file.xlsx xl/workbook.xml`(시트명), `xl/sharedStrings.xml`(라벨). -2. **양식 식별**: 타설비 템플릿 잔재 분리. 채울 슬롯 결정 → [04-stage-deliverables.md](04-stage-deliverables.md). - - 시트·컬럼 골격은 [05-form-schemas.md](05-form-schemas.md) 기준(ref 없어도 재현 가능). -3. **채움**: 이 프로젝트 사실로 값 작성. **출처(원본 파일·코드 경로) 명시**. - - 미확정 디바이스주소·축범위는 `(제안)` 표기. -4. **디자인 적용**: [08-design-system.md](08-design-system.md) 배너·뱃지·섹션헤더를 삽입한다. - - MD 최상단: 배너(§1) → 부제 바 순. - - 상태·유형 필드: 텍스트 대신 뱃지(§2·3) 사용. - - 진행률: `` 바(§4) 병기. - - 산출물 시트 구분 `##` 헤더: `` 적용(§5). -5. **배치**: 해당 `NN.단계명/<슬롯>/`에 저장. -6. **PPTX 생성**: [09-pptx-integration.md](09-pptx-integration.md) 참고. - - 2.설계 채움 완료 → `SW_설계서.pptx` (선택) - - 5.양산 채움 or 명시 요청 → `<설비명>_HMI_매뉴얼.pptx` (필수) - - MD 내용 → JSON spec → `ubisam-ppt-make/build_deck.py` → 슬롯에 저장 - - 임시 spec JSON 생성 후 pptx 완성 즉시 삭제 -7. **카드 갱신**: `_task.md`의 상태·진행률·첨부 매핑 갱신(PPTX 파일명 포함, [02-enums.md](02-enums.md)). -8. **기록**: `[작업일지]/<오늘>.md`에 한 일·다음 TODO. - -## xlsx 재생산 (from scratch · ref 불필요) -- `references/xlsxfill.py` — 스타일 상수 하드코딩 + scratch-build API. -- `references/build_02설계_xlsx.py` — PtoP 데이터 내장, 4종 xlsx 자동 생성. - **`ptop-deliverables` 경로 한정.** 타사 문서 재생산(rebuild)에는 쓰지 않는다 — 데이터가 하드코딩돼 매핑표를 반영할 수 없다. -- 실행: cwd=repo root, `PYTHONUTF8=1 py .claude/skills/ubisam-deliverables/references/build_02설계_xlsx.py` -- ref xlsx 없어도 동일 외형 재현. 스타일 상수 변경 시 xlsxfill.py만 수정. - -## pptx 재생산 (from scratch · ref 불필요) -- `references/build_02설계_pptx.py` — 슬라이드 스펙(22슬라이드) 내장, `ubisam-ppt-make/build_deck.py` 자동 호출. -- 실행: cwd=repo root, `PYTHONUTF8=1 py .claude/skills/ubisam-deliverables/references/build_02설계_pptx.py` -- 출력: `docs/[Ubisam산출물]/02.설계/설계리뷰_DR/SW_설계서.pptx` -- 임시 spec JSON 자동 생성·삭제. 표 높이 상한 5.3" 적용 — 푸터 비침범 보장. - -## MD 분할 규칙 -- 모든 산출/분석 MD는 **200줄 이내** (`rules.md` #4). 초과 시 주제별 분할 + 상호 링크(상대경로)로 매핑. -- 인덱스 문서(예: [분석] 폴더 README)에 1줄 포인터로 목록 유지. - -## 자기완결 보장 (ref 없이 동작) -- 이 스킬은 양식 골격을 [05-form-schemas.md](05-form-schemas.md)에 내장한다. -- `ref/`가 비어 있어도 트리·enum·양식 골격을 동일하게 생성한다. -- 새 양식 입수 시: 골격을 추출해 05 파일에 추가 → 이후 ref 없이 재현 가능. diff --git a/.claude/skills/ubisam-deliverables/references/07-fill-mapping.md b/.claude/skills/ubisam-deliverables/references/07-fill-mapping.md deleted file mode 100644 index b8298d4..0000000 --- a/.claude/skills/ubisam-deliverables/references/07-fill-mapping.md +++ /dev/null @@ -1,40 +0,0 @@ -# 07 · 자동 채움 매핑 (프로젝트 분석 → 산출물 필드) - -> "산출물 양식 필드 ← 호스트 레포의 진실원" 규칙. 프로젝트 비종속(휴리스틱) + PTOP 예시. -> 양식 시트·컬럼 골격은 [05-form-schemas.md](05-form-schemas.md), 절차는 [06-procedure.md](06-procedure.md). - -## 추출 휴리스틱 (어떤 프로젝트든) -| 추출 대상 | 탐색 방법(예) | -|---|---| -| 플랫폼/프레임워크 | `CLAUDE.md`, `*.csproj`/`*.sln`, `*.config` | -| PLC 기종·통신 | `grep -ri "melsec\|mx ?component\|slmp\|modbus\|ethernet/ip"` | -| 모션 컨트롤러·축 | `grep -ri "acs\|ajin\|axis\|ethercat\|servo"` | -| I/O 디바이스 | `grep -ri "beckhoff\|EL1\|EL2\|digital ?io\|io ?gate"` | -| Vision | `grep -ri "matrox\|MIL\|halcon\|cognex\|keyence"` | -| 메인 시퀀스 | `grep -ri "Seq\|Sequence\|Recipe\|Auto ?Run"` → 클래스/메서드 | -| 주소/메모리맵 | `*Address*.cs`, `*Map*`, `*.csv` 주소표 | - -## 설계 산출물 채움 매핑 (02.설계) -| 양식·필드 | 진실원(호스트) | -|---|---| -| 통신·제어 구성: 컨트롤러/통신 | 위 휴리스틱(PLC/모션/IO/Vision/Laser) | -| 모션축 정의: Axis·용도·범위 | 모션 설정·축 enum·파라미터 파일 | -| I/O 맵: 신호명·Type·모듈 | IO 정의/매핑 소스, 주소표 | -| PLC-PC 신호: 디바이스(M/D)·트리거 | PLC 인터페이스 주소 클래스(`*PLCController*Address*`) | -| 기능명세서: View·Function | UI/뷰모델 구조, 화면 클래스 | -| TactTime: Unit·단위동작 | 시퀀스 단계·동작 메서드 | - -미발견 값은 `(제안)` 표기 후 "최종 합의/소스 확인 시 확정" 단서. - -## PTOP 예시 (참고값) -- 설비: 각형 배터리 레이저 용접기(ILSOS OC5 PtoP Welder), Aurora 2.0 / .NET 4.8.1 / WPF -- PLC: Mitsubishi Melsec(MX Component) · Laser Scanner: RTC · Laser: IO Gate · Digital IO — 구현 클래스 `PAIX_PTOP`(`EquipmentSetup.cs:153`), 보드 타입은 `IOUnitConfig` 런타임 설정(단정 금지) -- 메인 시퀀스: `SeqAutoRunPTOP`(Recipe/Page 핸드셰이크 → 용접리스트 업로드 → 발진 → 완료비트) -- PLC 주소: `Machines/ILSOS_PrismaticRD_PTOP/Device/PLC/PLCController.Address.cs` - -> 이 예시는 PTOP 한정. 다른 프로젝트에선 위 휴리스틱으로 동일 절차를 적용해 값만 교체. - -## 채움 원칙 -- 모든 채운 값에 **출처 주석**(파일·심볼 경로) 부기. -- 상태/유형은 [02-enums.md](02-enums.md) enum 고정. -- 새 디바이스 종류 발견 시 [05-form-schemas.md](05-form-schemas.md) enum에 추가 후 사용. diff --git a/.claude/skills/ubisam-deliverables/references/08-design-system.md b/.claude/skills/ubisam-deliverables/references/08-design-system.md deleted file mode 100644 index 95eee28..0000000 --- a/.claude/skills/ubisam-deliverables/references/08-design-system.md +++ /dev/null @@ -1,126 +0,0 @@ -# 08 · Ubisam 산출물 디자인 시스템 - -> 모든 프로젝트의 산출물 MD에 공통 적용하는 HTML 색상 템플릿. -> VS Code Markdown Preview / Typora / GitLab 렌더링 기준. -> 스캐폴딩·채움 어느 단계에서든 이 파일을 참조해 배너·뱃지·진행률을 적용한다. - ---- - -## 색상 팔레트 - -| 구분 | 이름 | 색 코드 | 용도 | -|---|---|---|---| -| 배너 | 진네이비 | `#1F4E78` | 문서 최상단 제목 배너 | -| 헤더 | 파랑 | `#2E75B6` | 배너 하단 부제 바, 섹션 헤더 강조 | -| 상태·해야 할 일 | 회색 | `#757575` | 미착수 | -| 상태·분석 진행 | 청색 | `#1976D2` | 선택됨 | -| 상태·업무 진행중 | 파랑 | `#1565C0` | 진행 중 | -| 상태·진행 완료 | 연두 | `#689F38` | 완료 | -| 유형·오류수정 | 빨강 | `#D32F2F` | — | -| 유형·불합리 | 주황 | `#F57C00` | — | -| 유형·미팅 | 청록 | `#00796B` | 1.분석/협의 | -| 유형·설계 | 연두 | `#689F38` | 2.설계 | -| 유형·개발 | 파랑 | `#1976D2` | — | -| 유형·제작 | 남파랑 | `#283593` | 3.제작 | -| 유형·입고셋업 | 보라 | `#7B1FA2` | 4.셋업 | -| 유형·적용 및 모니터링 | 하늘 | `#0288D1` | 5.양산 | -| 유형·요청대응 | 남색 | `#1A237E` | 6.CS | - -> xlsx 색상과 동일 계열: 배너=`FF1F4E78`(진네이비), 헤더=`FF2E75B6`(파랑), 데이터 홀수=`FFDDEBF7`(연파랑). - ---- - -## 1. 문서 배너 (모든 산출물 MD 1번째 줄) - -```html -
-문서 제목 — 설비명 -
-
-근거: 소스 파일 경로  ·  플랫폼 정보 -
-``` - ---- - -## 2. 상태 뱃지 (값에 맞춰 색 코드 교체) - -```html -해야 할 일 -분석 진행 -업무 진행중 -진행 완료 -``` - ---- - -## 3. 유형 뱃지 - -```html -미팅 -설계 -개발 -제작 -입고셋업 -적용 및 모니터링 -요청대응 -오류수정 -불합리 -``` - ---- - -## 4. 진행률 바 - -```html - **0%** -``` - ---- - -## 5. 섹션 헤더 강조 (산출물 MD 내 시트 구분) - -```markdown -## 시트① 제목 -``` - ---- - -## 6. 미확정 경고 (GitHub Alerts) - -```markdown -> [!NOTE] -> 아래 값은 소스 분석 기반 `(제안)`. 현장 확인 후 확정. -``` - ---- - -## 7. _task.md 완성 템플릿 (디자인 포함) - -단계명·프로젝트명·코드·유형·상태·진행률 토큰 교체 후 사용. - -```markdown -
-{N}.{단계명} — {프로젝트명} -
-
-{프로젝트코드}-{일련번호} -
- -| 필드 | 값 | -|---|---| -| 유형 | {유형명} | -| 상태 | 해야 할 일 | -| 담당자 / 참조자 | {담당자} / {참조자} | -| 진행률 | **0%** | -| Hashtag | {태그1} / {태그2} | -``` - ---- - -## 적용 규칙 -- **항상 배너 먼저**: 산출물 MD 생성 시 본문 앞에 배너 블록을 삽입한다. -- **뱃지 > 텍스트**: 상태·유형은 텍스트가 아닌 뱃지 HTML로 표기한다. -- **진행률 bar 병기**: `` 태그 + bold 숫자를 함께 쓴다(텍스트 렌더러 폴백). -- **섹션 헤더**: 산출물 내 시트 구분 `##` 제목은 `` 적용. -- **README·_meta enum**: 동일 색상 체계를 그대로 적용한다. diff --git a/.claude/skills/ubisam-deliverables/references/09-pptx-integration.md b/.claude/skills/ubisam-deliverables/references/09-pptx-integration.md deleted file mode 100644 index 9b343b3..0000000 --- a/.claude/skills/ubisam-deliverables/references/09-pptx-integration.md +++ /dev/null @@ -1,109 +0,0 @@ -# 09 · PPTX 통합 — ubisam-ppt-make 연동 - -> **역할 분리 원칙** -> - `ubisam-deliverables`: spec JSON 준비 + 슬롯 배치 담당 (PPTX 직접 생성 금지) -> - `ubisam-ppt-make`: PPTX 렌더링 엔진 (`build_deck.py`) — 레이아웃·디자인 토큰 정의 소유자 -> -> PPTX 생성은 항상 `.claude/skills/ubisam-ppt-make/build_deck.py`를 호출한다. -> 레이아웃 타입·디자인 규칙은 `ubisam-ppt-make/SKILL.md`가 단일 진실 소스(SSoT). -> 표 높이 상한 `_TABLE_MAX_H=5.3"` 등 렌더링 규칙은 `build_deck.py` 내부에서 보장. - ---- - -## 생성 타이밍 - -| 트리거 | 생성 PPTX | 저장 슬롯 | -|---|---|---| -| 2.설계 채움 완료 | SW 설계서 (선택) | `02.설계/설계리뷰_DR/SW_설계서.pptx` | -| 5.양산 채움 or 명시 요청 | 운영매뉴얼_HMI | `05.양산/운영매뉴얼_HMI/<설비명>_HMI_매뉴얼.pptx` | -| 명시 요청 ("pptx 만들어줘") | 해당 단계 산출물 | 해당 슬롯 | - ---- - -## 실행 절차 - -### 2.설계 SW 설계서 — 자동 재생산 (권장) -``` -PYTHONUTF8=1 py .claude/skills/ubisam-deliverables/references/build_02설계_pptx.py -``` -- 슬라이드 스펙 내장 · 임시 JSON 자동 생성/삭제 · `build_deck.py` 호출 · 출력까지 자동 -- 출력: `docs/[Ubisam산출물]/02.설계/설계리뷰_DR/SW_설계서.pptx` - -### 신규 단계 PPTX — 수동 절차 -``` -1. 해당 단계 MD 파일 읽기 -2. 아래 매핑표로 slide 오브젝트 목록 작성 -3. JSON spec 생성 → 스크래치 파일(임시)로 저장 -4. 저장소 루트에서 실행 (`PYTHONUTF8=1`은 반드시 같은 줄 접두 — 별도 줄이면 적용되지 않는다): - PYTHONUTF8=1 py .claude/skills/ubisam-ppt-make/build_deck.py \ - --input .json --output <슬롯경로>.pptx -5. 임시 spec 파일 삭제 -6. _task.md 첨부 목록 갱신 -``` - ---- - -## A. 2.설계 → SW 설계서 (선택) - -소스 MD → slide 타입 매핑: - -| MD 소스 | slide type | 비고 | -|---|---|---| -| — | `cover` | `tag="SW DESIGN DOCUMENT"` (키 이름은 `tag` — `doc_tag`는 무시된다) | -| — | `history` | 버전/변경이력 (사용자 입력 or 빈 행) | -| 각 산출물 목록 | `agenda` | 최대 6항목 | -| 기능명세서 §메뉴구조 | `table` | headers: 메인메뉴/권한/서브뷰/기능 | -| 기능명세서 §View별기능 | `table` | View별 1슬라이드씩 | -| 제어시퀀스_인터락_정의서.md §mermaid 노드 | `flow` | steps: 노드명+코드+kind | -| PLC신호정의서 §PC→PLC | `table` | headers: No/신호명/디바이스/Type/의미 | -| PLC신호정의서 §PLC→PC | `table` | 동일 구조 | -| 모션축_IO맵 §통신구성 | `table` | | -| 모션축_IO맵 §I/O맵 DI/DO | `table` | | -| TactTime §PC TactTime | `table` | | -| — | `closing` | | - ---- - -## B. 5.양산 → 운영매뉴얼_HMI (필수) - -| MD/소스 | slide type | 비고 | -|---|---|---| -| — | `cover` | `tag="HMI OPERATION MANUAL"` | -| — | `history` | | -| View 목록 | `agenda` | AutoRun/Recipe/Manual/Calibration/Monitoring/Alarm | -| 각 View | `divider` | View명 섹션 구분 | -| 각 View §기능목록 | `screen_guide` | image 없으면 caption만 | -| 각 View §조작절차 | `procedure` | steps: title+desc | -| 알람 목록 | `alarm` | rows: 코드/알람명/원인/조치 | -| — | `closing` | | - ---- - -## spec JSON 최소 골격 - -```json -{ - "doc_title": "{설비명} SW 설계서", - "slides": [ - {"type": "cover", "tag": "SW DESIGN DOCUMENT", - "title": "{설비명} SW 설계서", - "subtitles": ["{설비 설명}"], - "team": "{조직}", - "contacts": ["{담당자}"]}, - {"type": "history", "rows": []}, - {"type": "agenda", "items": []}, - {"type": "closing", "title": "Thank You", - "team": "{조직}", "contacts": []} - ] -} -``` - -> 캔버스 배경은 `build_deck.py:55-73`이 **`WHITE`** 로 고정한다(`BG_SOFT`는 패널·표 fill 전용). -> spec JSON으로 바꿀 수 없다. - ---- - -## 불변 규칙 -- spec JSON은 임시파일로 생성 후 pptx 완성 즉시 삭제 (작업 완료 시 정리). -- PPTX 저장 후 `_task.md` 첨부 목록에 파일명 추가. -- `ubisam-ppt-make/SKILL.md` §Verification — PowerPoint COM 가능 시 PNG 렌더 검증, 불가 시 폰트 감사만 하고 `미수행` 명시. diff --git a/.claude/skills/ubisam-deliverables/references/build_02설계_pptx.py b/.claude/skills/ubisam-deliverables/references/build_02설계_pptx.py deleted file mode 100644 index 496f7d7..0000000 --- a/.claude/skills/ubisam-deliverables/references/build_02설계_pptx.py +++ /dev/null @@ -1,355 +0,0 @@ -# -*- coding: utf-8 -*- -""" -ILSOS PrismaticRD PTOP — 2.설계 SW_설계서.pptx 자동 생성 스크립트. - -실행: - PYTHONUTF8=1 py .claude/skills/ubisam-deliverables/references/build_02설계_pptx.py - -출력: docs/[Ubisam산출물]/02.설계/설계리뷰_DR/SW_설계서.pptx -""" -import os, io, json, subprocess, sys, tempfile - -HERE = os.path.dirname(os.path.abspath(__file__)) -REPO = os.path.abspath(os.path.join(HERE, "..", "..", "..", "..")) -BUILDER = os.path.join(REPO, ".claude", "skills", "ubisam-ppt-make", "build_deck.py") -OUTPUT = os.path.join(REPO, "docs", "[Ubisam산출물]", "02.설계", "설계리뷰_DR", "SW_설계서.pptx") - -# 프로젝트 메타의 유일 진실원은 _meta/project.yaml 이다 (ubisam-format-map §5). -# 이 스크립트에 조직·담당자를 하드코딩하면 다른 프로젝트로 재사용할 때 타사 값이 그대로 새어 나간다. -_PROJECT_YAML = os.path.join(REPO, "docs", "[Ubisam산출물]", "_meta", "project.yaml") -_META_CACHE = None - - -def _meta(path, default="미정 — 확인 필요"): - """project.yaml에서 점 경로(예: "people.pl")를 읽는다. - - 파일·키가 없거나 값이 미치환 토큰("{PL}")이면 default를 그대로 렌더링해 - '미정'임이 산출물에 드러나게 한다 — 조용히 남의 값이 찍히는 것보다 낫다. - """ - global _META_CACHE - if _META_CACHE is None: - try: - import yaml - with io.open(_PROJECT_YAML, encoding="utf-8") as f: - _META_CACHE = yaml.safe_load(f) or {} - except Exception: - _META_CACHE = {} # 파일 부재·파싱 실패는 정상 — default가 쓰인다 - cur = _META_CACHE - for k in path.split("."): - if not isinstance(cur, dict) or k not in cur: - return default - cur = cur[k] - v = str(cur).strip() if cur is not None else "" - return default if (not v or v.startswith("{")) else v - - -SPEC = { - "doc_title": "ILSOS PrismaticRD PTOP SW 설계서", - "slides": [ - { - "type": "cover", - "tag": "SW DESIGN DOCUMENT", - "title": "ILSOS PrismaticRD PTOP\nSW 설계서", - "subtitles": [ - "LGES OC5 PtoP Welder — Prismatic 전지 점 용접 자동화 SW", - "Aurora 2.0 / .NET 4.8.1 / WPF · MX Component · ACS EtherCAT · Digital IO(보드타입 런타임 설정 — 미확정)" - ], - # 조직·담당자는 docs/[Ubisam산출물]/_meta/project.yaml 이 유일 진실원이다. - # 파일이 없으면 아래 자리표시자를 그대로 렌더링해 "미정"임이 드러나게 한다. - "team": _meta("org.team"), - "contacts": [_meta("people.pl")] - }, - { - "type": "history", - "no": "00.", - "title": "변경 이력", - "subtitle": "Revision History", - "rows": [ - ["01", "0.1", _meta("schedule.contract_date", "미정"), _meta("people.registrant"), - "소스 기반 최초 작성 (기능명세·시퀀스·신호정의·IO맵·TactTime)"], - ["02", "0.2", _meta("schedule.contract_date", "미정"), _meta("people.registrant"), - "SW_설계서.pptx 최초 생성 (build_02설계_pptx.py)"] - ] - }, - { - "type": "agenda", - "title": "Contents", - "subtitle": "목차", - "items": [ - {"no": "01", "title": "기능명세서", "sub": "메뉴 구조 · View별 기능"}, - {"no": "02", "title": "제어 시퀀스 / 인터록", "sub": "SeqAutoRunPTOP · 인터록 정의"}, - {"no": "03", "title": "PLC-PC 신호 정의", "sub": "통신 사양 · PC↔PLC 신호 목록"}, - {"no": "04", "title": "모션축 / IO 맵", "sub": "축 정의 · DI/DO 맵"}, - {"no": "05", "title": "TactTime 산정서", "sub": "자동 1사이클 단위동작별 T/T"} - ] - }, - # ── 01. 기능명세서 ────────────────────────────────────────────── - {"type": "divider", "no": "01", "title": "기능명세서", "subtitle": "UI / Function Specification"}, - { - "type": "table", - "no": "01.", "title": "메뉴 구조", - "subtitle": "RegisterViews — 메인 메뉴 · 권한 · 서브뷰 · 기능 요약", - "headers": ["메인 메뉴", "권한", "서브뷰", "기능"], - "widths": [1.6, 1.2, 3.4, 5.2], "center_cols": [0, 1], - "rows": [ - ["AutoRun", "NONE", "UCMainAutoRun", "자동 운전 메인(SeqAutoRun 연동), 페이지/상태 표시"], - ["Recipe", "NONE", "UCRecipe / UCRecipeChangeHistory / UCModel", "레시피 편집·변경이력·모델"], - ["Manual", "NONE", "UCManualScannerOperation / UCManualModelFinder", "스캐너 수동조작·모델 파인더"], - ["Calibration","NONE", "UCScannerCalibration / UCCameraPixelResolution", "스캐너 보정·픽셀 해상도"], - ["Monitoring", "NONE", "UCPLCBit / UCPLCWord / UCIOInterfaceView", "PLC 비트(M)·워드(D)·IO 모니터링"], - ["Device", "LEVEL3", "DeviceSettingView", "디바이스 설정"], - ["Setting", "LEVEL1", "EquipSettingView / LogSettingView / AutoBackupView2", "장비·로그·자동백업 설정"], - ["Alarm", "NONE", "AlarmHistoryView / AlarmDescView", "알람 이력·설명"] - ] - }, - { - "type": "table", - "no": "01.", "title": "View별 기능 (1/2)", - "subtitle": "MainView · RecipeView · ManualView", - "headers": ["View", "no", "기능 영역", "기능명", "연동"], - "widths": [1.6, 0.6, 1.8, 2.8, 4.6], "center_cols": [0, 1], - "rows": [ - ["MainView", "1", "운전", "StartSequence / Stop", "SeqAutoRunPTOP"], - ["MainView", "2", "상태", "UpdatePageNum", "EVENT_AUTO_RUN_UPDATE_PAGENUM"], - ["MainView", "3", "상태", "WorkingPosition", "eWorkingPosition"], - ["MainView", "4", "운전", "Auto→Manual+Resume", "bit15(PLC_WELD_READY_REQ)"], - ["MainView", "5", "표시", "ScannerCanvasCtrlTeaching", "레이어/오브젝트"], - ["RecipeView", "1", "레시피", "ActivateRecipe", "RecipeManager"], - ["RecipeView", "2", "레시피", "RecipeChangeHistory", "RchHandler"], - ["RecipeView", "3", "모델", "UCModel / EquipmentSpecificModel", "EquipmentSpecificModel_PTOP"], - ["ManualView", "1", "수동", "ScannerOperation", "CommonDeviceIds.Scanner"], - ["ManualView", "2", "수동", "ModelFinder", "UCManualModelFinder"] - ] - }, - { - "type": "table", - "no": "01.", "title": "View별 기능 (2/2)", - "subtitle": "MonitoringView · CalibrationView · SettingView · AlarmView", - "headers": ["View", "no", "기능 영역", "기능명", "연동"], - "widths": [1.8, 0.6, 1.8, 2.8, 4.4], "center_cols": [0, 1], - "rows": [ - ["MonitoringView", "1", "모니터링", "PLCBitMonitoring", "ePLCDevice.M"], - ["MonitoringView", "2", "모니터링", "PLCWordMonitoring", "ePLCDevice.D"], - ["MonitoringView", "3", "모니터링", "IOInterfaceView", "IODevice"], - ["CalibrationView", "1", "보정", "UCScannerCalibration", "스캐너 보정"], - ["CalibrationView", "2", "보정", "UCCameraPixelResolution","카메라 픽셀 해상도"], - ["SettingView", "1", "설정", "EquipSettingView", "장비 설정"], - ["SettingView", "2", "설정", "LogSettingView / AutoBackupView2", "로그·자동백업"], - ["AlarmView", "1", "알람", "AlarmHistoryView", "AlarmCode_PTOP"], - ["AlarmView", "2", "알람", "AlarmDescView", "AlarmManager_PTOP"] - ] - }, - # ── 02. 제어 시퀀스 / 인터록 ──────────────────────────────────── - {"type": "divider", "no": "02", "title": "제어 시퀀스 / 인터록", "subtitle": "Control Sequence & Interlock"}, - { - "type": "flow", - "no": "02.", "title": "SeqAutoRunPTOP — 자동 시퀀스 (초기화 ~ 업로드)", - "subtitle": "Sequences/SeqAutoRunPTOP.cs — Builder() 노드 흐름 (1/2)", - "steps": [ - {"title": "Sequence_Enter", "code": "레시피/장비 초기화 · PC_AUTO_STATUS ON", "kind": "proc"}, - {"title": "CheckInitCondition", "code": "초기 조건 판단", "kind": "dec"}, - {"title": "CheckPageNo", "code": "PLC_PAGE_CHANGE_REQ(0x08) 대기", "kind": "proc"}, - {"title": "CheckRecipeNoComp", "code": "PLC_RECIPE_NO 확정/전환 · PC_RECIPE_NO 에코", "kind": "proc"}, - {"title": "CheckPageNoComp", "code": "PLC_PAGE_NO 3회 검증 · PC_PAGE_CHANGE_COMPLETE ACK", "kind": "proc"}, - {"title": "SeqUploadWeldingList","code": "레이어 선택 → 용접리스트 업로드 · offset(D70510) 적용", "kind": "proc"} - ], - "branch": {"title": "Resume", "sub": "핸드셰이크 스킵"} - }, - { - "type": "flow", - "no": "02.", "title": "SeqAutoRunPTOP — 자동 시퀀스 (발진 ~ 완료)", - "subtitle": "Sequences/SeqAutoRunPTOP.cs — Builder() 노드 흐름 (2/2)", - "steps": [ - {"title": "WeldingStartReadBit", "code": "PLC_WELD_TRIGGER_REQ(0x10) 대기", "kind": "proc"}, - {"title": "PreScoutCheck", "code": "M70509 ON → PreScout 실행", "kind": "dec"}, - {"title": "WaitWeldingStart", "code": "PC_WELD_TRIGGER_ACK ON / WELD_COMPLETE OFF", "kind": "proc"}, - {"title": "ExecuteWelding", "code": "HeadTheta 인터락 → Gate ON(15ms) → ExecuteList → Gate OFF", "kind": "proc"}, - {"title": "WriteWeldComplete", "code": "PC_WELD_TRIGGER_ACK OFF · PC_WELD_COMPLETE ON", "kind": "proc"}, - {"title": "CheckCycleStop", "code": "루프백 or SaveResult → WriteCompletionPLCBit", "kind": "dec"} - ], - "branch": {"title": "PostScout", "sub": "M70509 ON 시 실행"} - }, - { - "type": "table", - "no": "02.", "title": "인터록 정의", - "subtitle": "LaserInterlockSetting.cs · SeqAutoRunPTOP.cs", - "headers": ["#", "인터록", "조건", "동작"], - "widths": [0.5, 2.3, 4.0, 4.6], "center_cols": [0], - "rows": [ - ["1", "Head Theta 발진 게이트", "LaserInterlockSetting.HeadThetaInterlockEnabled ON · Front/Down ±tol 벗어남", "발진 차단 (ALARM_LASER_HEAD_THETA_INTERLOCK). PLC 미연결 시 fail-closed"], - ["2", "레시피별 방향 차단", "RecipeLaserInterlock.Front/Down 체크", "해당 방향 구역이면 발진 차단"], - ["3", "중알람(Heavy)", "PLC_HEAVY_ALARM_STATUS(0x05)", "AlarmManager_PTOP.StopSequenceByAlarm → 시퀀스 정지"], - ["4", "Door / EMO", "PLC_DOOR_INTERLOCK(0x06) / PLC_EMO_STATUS(0x07)", "안전 정지"], - ["5", "업로드 실패", "용접 오브젝트 0개 / Upload Success=false", "시퀀스 중단 (return null)"] - ] - }, - # ── 03. PLC-PC 신호 정의서 ────────────────────────────────────── - {"type": "divider", "no": "03", "title": "PLC-PC 신호 정의서", "subtitle": "PLC Interface Signal Definition"}, - { - "type": "table", - "no": "03.", "title": "통신 사양", - "subtitle": "EquipmentSetup.cs · PLCController.Address.cs", - "headers": ["항목", "내용"], - "widths": [2.8, 8.6], "center_cols": [], - "rows": [ - ["PLC 기종", "Mitsubishi Melsec"], - ["통신 방식", "MX Component (ePLCNetType.MXComponent) — EquipmentSetup.RegisterDevices()"], - ["맵 파일", "CSV (PLCMMapFileType.CSV)"], - ["데이터 갱신", "폴링(10ms 주기 ReadBit/ReadWord) + 이벤트 비트(REQ/ACK)"], - ["디바이스 영역", "비트=M, 워드=D (입력 M70500/D70500 · 출력 M70000/D70000 — 제안)"], - ["핸드셰이크 규칙", "요청(REQ)→처리→완료(ACK/COMPLETE). 단일 트리거 PLC_PAGE_CHANGE_REQ(0x08)"], - ["인터락", "Door(0x06)·EMO(0x07)·Heavy알람(0x05) → 시퀀스 정지. HeadTheta(D70510) 발진 게이트"], - ["Watchdog", "PLC_LIVE_STATUS(0x00) ↔ PC_LIVE_STATUS(0x00) Alive 토글"] - ] - }, - { - "type": "table", - "no": "03.", "title": "PC → PLC 신호 목록", - "subtitle": "eBitOutput / eWordOutput (Write) — 주요 신호", - "headers": ["No", "신호명(enum)", "디바이스", "Type", "의미"], - "widths": [0.7, 3.3, 1.4, 0.8, 5.2], "center_cols": [0, 2, 3], - "rows": [ - ["0x00", "PC_LIVE_STATUS", "M70000(제안)", "BIT", "PC Alive 토글 (Watchdog)"], - ["0x01", "PC_AUTO_STATUS", "M70001", "BIT", "Auto 상태 — Enter 시 ON"], - ["0x05", "PC_HEAVY_ALARM_STATUS", "M70005", "BIT", "중알람"], - ["0x06", "PC_DOOR_INTERLOCK", "M70006", "BIT", "Door 인터락"], - ["0x07", "PC_EMO_STATUS", "M70007", "BIT", "EMO"], - ["0x08", "PC_PAGE_CHANGE_COMPLETE", "M70008", "BIT", "페이지 확정 ACK — PageNo 일치 시 ON"], - ["0x0F", "PC_WELD_READY_ACK", "M70015", "BIT", "Resume ACK (bit15, 260621)"], - ["0x10", "PC_WELD_TRIGGER_ACK", "M70016", "BIT", "용접 트리거 ACK"], - ["0x11", "PC_WELD_BUSY", "M70017", "BIT", "Laser On 표시(발진중)"], - ["0x12", "PC_WELD_COMPLETE", "M70018", "BIT", "용접 완료"], - ["D0x01", "PC_PAGE_NO", "D70001", "INT", "페이지 번호 에코"], - ["D0x02", "PC_RECIPE_NO", "D70002", "INT", "레시피 번호 에코"] - ] - }, - { - "type": "table", - "no": "03.", "title": "PLC → PC 신호 목록", - "subtitle": "eBitInput / eWordInput (Read) — 주요 신호", - "headers": ["No", "신호명(enum)", "디바이스", "Type", "의미"], - "widths": [0.7, 3.3, 1.4, 0.8, 5.2], "center_cols": [0, 2, 3], - "rows": [ - ["0x00", "PLC_LIVE_STATUS", "M70500(제안)", "BIT", "PLC Alive (Watchdog)"], - ["0x05", "PLC_HEAVY_ALARM_STATUS", "M70505", "BIT", "중알람 → 시퀀스 정지"], - ["0x06", "PLC_DOOR_INTERLOCK", "M70506", "BIT", "Door 인터락"], - ["0x07", "PLC_EMO_STATUS", "M70507", "BIT", "EMO"], - ["0x08", "PLC_PAGE_CHANGE_REQ", "M70508", "BIT", "단일 게이트 트리거 — PageNo+RecipeNo 확정"], - ["0x09", "PLC_SCOUT_ENABLE", "M70509", "BIT", "Scout 상시 ON → 용접 전/후 Scout"], - ["0x0F", "PLC_WELD_READY_REQ", "M70515", "BIT", "Weld_01 Ready → Resume 트리거 (bit15)"], - ["0x10", "PLC_WELD_TRIGGER_REQ", "M70516", "BIT", "용접 발진 요청"], - ["D0x01", "PLC_PAGE_NO", "D70501", "INT", "페이지 번호 (1-base, 3회 검증)"], - ["D0x02", "PLC_RECIPE_NO", "D70502", "INT", "레시피 번호 (11/21/22/31/32)"], - ["D0x0A", "HEAD_THETA_POSITION", "D70510", "INT", "Laser1 Head Theta — 발진 인터락"] - ] - }, - # ── 04. 모션축 / IO 맵 ────────────────────────────────────────── - {"type": "divider", "no": "04", "title": "모션축 / IO 맵", "subtitle": "Motion Axis & I/O Map"}, - { - "type": "table", - "no": "04.", "title": "통신·제어 구성", - "subtitle": "EquipmentSetup.cs · PAIX_PTOP.cs · architecture.md §4", - "headers": ["구분", "대상", "컨트롤러/디바이스", "통신/버스", "수량·범위"], - "widths": [1.8, 1.8, 2.8, 2.0, 3.0], "center_cols": [0], - "rows": [ - ["PLC통신", "외부 신호 제어", "Mitsubishi Melsec", "MX Component", "1"], - ["I/O", "디지털 IO", "(제안) IOUnitConfig.BoardType 확인 필요", "필드버스", "DI/DO"], - ["Laser", "Core/Ring 레이저", "IO Gate(TruPulse nano 계열)", "DO 게이트", "2(Core+Ring)"], - ["Scanner", "레이저 스캐너", "RTC LaserScanner", "RTC", "1"], - ["모션(Servo)", "X/Y 축", "ACS SPiiPlus", "EtherCAT", "2축 (제안)"], - ["모션(Servo)", "Z 축", "(제안) AuroraMotionBoard", "보드", "1축 (제안)"], - ["Vision", "카메라/측정", "MIL 기반 AuroraVision", "—", "(현재 미사용)"], - ["상/하위(MES)", "호스트 연동", "Stream(LBAD/RPC)", "TCP", "옵션"] - ] - }, - { - "type": "table", - "no": "04.", "title": "모션축 정의", - "subtitle": "ACS SPiiPlus(EtherCAT) · AuroraMotionBoard(보드타입 미확정) — 파라미터 미확정(제안)", - "headers": ["Axis", "축명", "용도", "컨트롤러/통신", "행정/범위", "최대속도", "Home방식"], - "widths": [0.7, 0.8, 1.7, 2.5, 1.7, 1.5, 2.5], "center_cols": [0, 1], - "rows": [ - ["0", "X", "셀 위치 X", "ACS SPiiPlus / EtherCAT", "(제안)", "(제안)", "(제안)"], - ["1", "Y", "셀 위치 Y", "ACS SPiiPlus / EtherCAT", "(제안)", "(제안)", "(제안)"], - ["2", "Z", "포커스/높이", "(제안) AuroraMotionBoard", "(제안)", "(제안)", "(제안)"], - ["—", "Scanner θ/XY", "빔 편향(갈바노)", "RTC LaserScanner", "List 기반 Jump/Mark", "—", "보정테이블"] - ] - }, - { - "type": "table", - "no": "04.", "title": "I/O 맵 — DI / DO", - "subtitle": "PAIX_PTOP.ePrismaticDIAddress / ePrismaticDOAddress (보드타입 런타임 설정)", - "headers": ["구분", "CH(No)", "신호명", "Active", "설명"], - "widths": [0.8, 1.0, 3.2, 1.0, 5.4], "center_cols": [0, 1, 3], - "rows": [ - ["DI", "9", "CoreLaser_Laser_Ready", "High", "Core 레이저 Ready"], - ["DI", "10", "CoreLaser_Error_State", "High", "Core 레이저 에러"], - ["DI", "11", "CoreLaser_Laser_Output_State", "High", "Core 발진 출력 상태"], - ["DI", "12", "CoreLaser_Control_Status", "High", "Core 제어 상태"], - ["DI", "13", "RingLaser_Laser_Ready", "High", "Ring 레이저 Ready"], - ["DI", "14", "RingLaser_Error_State", "High", "Ring 레이저 에러"], - ["DI", "15", "RingLaser_Laser_Output_State", "High", "Ring 발진 출력 상태"], - ["DI", "23", "RingLaser_Control_Status", "High", "Ring 제어 상태"], - ["DO", "9", "CoreLaser_Control", "High", "Core 레이저 게이트(발진 ON/OFF)"], - ["DO", "10", "CoreLaser_ErrorClearing", "High", "Core 에러 클리어"], - ["DO", "13", "RingLaser_Control", "High", "Ring 레이저 게이트(발진 ON/OFF)"], - ["DO", "14", "RingLaser_ErrorClearing", "High", "Ring 에러 클리어"], - ["DO", "17", "EX_Red_Control", "High", "EX Red(가이드/표시등) 제어"] - ] - }, - # ── 05. TactTime 산정서 ───────────────────────────────────────── - {"type": "divider", "no": "05", "title": "TactTime 산정서", "subtitle": "Tact Time Analysis"}, - { - "type": "table", - "no": "05.", "title": "PC TactTime — 자동 1사이클 (음극 1페이지 기준)", - "subtitle": "SeqAutoRunPTOP.cs 지연·로그 상수 기준 (제안 — 현장 실측 시 확정)", - "headers": ["Unit", "단위동작", "T/T(ms)", "PC", "PLC", "출처"], - "widths": [0.7, 3.0, 1.3, 0.6, 0.6, 5.2], "center_cols": [0, 2, 3, 4], - "rows": [ - ["1", "Page Change 요청 대기", "가변", "●", "●", "CheckPageNo (폴링 10ms, timeout 60s)"], - ["2", "Recipe 확정/전환", "~0~수백","●", "—", "CheckRecipeNoComp (동일이면 ~0, 전환 시 Activate+reload)"], - ["3", "Page 3회 검증", "~600", "●", "●", "CheckPageNoComp (200ms×3)"], - ["4", "용접리스트 업로드", "가변", "●", "—", "SeqUploadWeldingList (라인수 의존)"], - ["5", "발진 요청 대기", "가변", "●", "●", "WeldingStartReadBit"], - ["6", "준비 응답", "~205", "●", "●", "WaitWeldingStart (200+5ms)"], - ["7", "Gate ON delay", "15", "●", "—", "laserEmissionGateDelayMs (TruPulse 매뉴얼 ≥10ms)"], - ["8", "실제 발진(ExecuteList)", "미측정", "—", "—", "런타임 값 — 실측 필요(로그 TactTime, 라인수 의존)"], - ["9", "Gate OFF + BUSY OFF", "~50", "●", "—", "ExecuteWelding 후미"], - ["10", "Jump+CorrectionTable 복귀", "~500", "—", "—", "Thread.Sleep(500)"], - ["11", "완료비트 송신", "~55", "●", "●", "WriteWeldComplete (50+5ms)"], - ["(옵션)","Pre/Post Scout", "+100/회","●","Vision","SCOUT_PROCEED_DELAY_MS, M70509 ON 시"] - ] - }, - { - "type": "closing", - "title": "Thank You", - "message": "본 설계서는 소스코드 분석 기반 0.2버전입니다. 파라미터 확정 후 갱신 예정.", - "team": _meta("org.team"), - "contacts": [_meta("people.pl")] - } - ] -} - - -def main(): - os.makedirs(os.path.dirname(OUTPUT), exist_ok=True) - fd, spec_path = tempfile.mkstemp(suffix=".json", prefix="sw_spec_") - try: - with os.fdopen(fd, "w", encoding="utf-8") as f: - json.dump(SPEC, f, ensure_ascii=False, indent=2) - result = subprocess.run( - [sys.executable, BUILDER, "--input", spec_path, "--output", OUTPUT], - capture_output=True, text=True, encoding="utf-8" - ) - if result.stdout: - print(result.stdout.strip()) - if result.returncode != 0: - print("[ERROR]", result.stderr.strip(), file=sys.stderr) - sys.exit(result.returncode) - finally: - if os.path.exists(spec_path): - os.remove(spec_path) - - -if __name__ == "__main__": - main() diff --git a/.claude/skills/ubisam-deliverables/references/build_02설계_xlsx.py b/.claude/skills/ubisam-deliverables/references/build_02설계_xlsx.py deleted file mode 100644 index 51fc014..0000000 --- a/.claude/skills/ubisam-deliverables/references/build_02설계_xlsx.py +++ /dev/null @@ -1,481 +0,0 @@ -# -*- coding: utf-8 -*- -""" -build_02설계_xlsx.py — PtoP Welder(가접용접기) 02.설계 산출물 재생산 -──────────────────────────────────────────────────────────────────── -LG PRI 표준 양식(ref 파일 불필요 · 완전 독립 실행). -스타일은 xlsxfill.py 에 하드코딩된 상수를 사용. - -전제조건: - - Python 3.9+ - - openpyxl >= 3.1 (pip install openpyxl) - -실행 (저장소 루트에서 한 줄. PYTHONUTF8은 반드시 같은 줄 접두 — 별도 줄이면 적용되지 않는다): - PYTHONUTF8=1 py .claude/skills/ubisam-deliverables/references/build_02설계_xlsx.py - -출력: - docs/[Ubisam산출물]/02.설계/IO_DB설계/PLC_PC_인터페이스_신호정의서.xlsx - docs/[Ubisam산출물]/02.설계/IO_DB설계/모션축_IO맵_정의서.xlsx - docs/[Ubisam산출물]/02.설계/UIUX_기능설계/기능명세서.xlsx - docs/[Ubisam산출물]/02.설계/시퀀스_인터록/TactTime_산정서.xlsx -""" -import sys, os, datetime -sys.path.insert(0, os.path.dirname(__file__)) -from xlsxfill import ( - make_workbook, set_col_widths, set_row_height, - write_banner, write_header_row, write_data_rows, group_merge, - BANNER_FONT, BANNER_FILL, BANNER_BORDER, BANNER_ALIGN, - SUBBANNER_FONT, SUBBANNER_BORDER, SUBBANNER_ALIGN, - HEADER_FONT, HEADER_FILL, HEADER_BORDER_FIRST, HEADER_BORDER_MID, HEADER_BORDER_LAST, - DATA_FONT, DATA_FILL_ODD, DATA_FILL_EVEN, - DATA_BORDER_FIRST, DATA_BORDER_MID, DATA_BORDER_LAST, - DATA_ALIGN_L, DATA_ALIGN_C, - FUNC_BANNER_FONT, FUNC_HEADER_FONT, FUNC_HEADER_BORDER, - FUNC_DATA_FONT, FUNC_DATA_BORDER, FUNC_DATA_ALIGN, - TACT_FONT, TACT_BORDER, TACT_ALIGN, TACT_ALIGN_L, - _apply, _border, -) -from openpyxl.styles import Font, PatternFill, Alignment -from openpyxl.utils import get_column_letter as GL - -OUT_DIR = "docs/[Ubisam산출물]/02.설계/" -TODAY = datetime.date.today() # 실행일 자동 반영 - - -# ══════════════════════════════════════════════════════ -# 1. PLC-PC 인터페이스 신호 정의서 -# 탭: 통신 사양 | PC→PLC (Write) | PLC→PC (Read) | 핸드셰이크 시퀀스 -# ══════════════════════════════════════════════════════ -def build_plcpc(): - wb = make_workbook() - OUT = OUT_DIR + "IO_DB설계/PLC_PC_인터페이스_신호정의서.xlsx" - - # ── 통신 사양 ────────────────────────────────── - ws = wb.create_sheet("통신 사양") - set_col_widths(ws, {"A":"3.7","B":24,"C":106}) - write_banner(ws, 2, 2, 3, - "PtoP Welder(가접용접기) ↔ PLC 인터페이스 통신 사양", - "PtoP Welder(가접용접기) — MX Component / 단일 게이트(PAGE_REQ) 핸드셰이크 · 디바이스 주소=제안(M70000/M70500 베이스)") - write_header_row(ws, 4, 2, ["항목", "내용"]) - comm = [ - ["PLC 기종", "Mitsubishi Melsec"], - ["통신 방식", "MX Component (ePLCNetType.MXComponent)"], - ["맵 파일", "CSV (PLCMMapFileType.CSV)"], - ["데이터 갱신", "폴링(10ms) + 이벤트 비트(REQ/ACK)"], - ["디바이스 영역","비트=M, 워드=D (PC Write M70000~/D70000~, PLC Read M70500~/D70500~)"], - ["핸드셰이크", "REQ→처리→ACK/COMPLETE. 단일 트리거 PLC_PAGE_CHANGE_REQ"], - ["좌표·실수", "워드 INT(short). Offset/변위 INT. 스케일 ×1(필요시 ×1000)"], - ["Watchdog", "PLC_LIVE_STATUS(0x00) ↔ PC_LIVE_STATUS(0x00)"], - ["인터락", "Door(0x06)/EMO(0x07)/Heavy(0x05)→정지, HeadTheta(D70510) 발진 인터락"], - ["주의", "주소=제안. 2nd 블록(0x65~)은 양극(P) 예비, 현재 음극만 사용"], - ] - write_data_rows(ws, 5, 2, comm, center_cols={0}) - - # ── PC→PLC (Write) ───────────────────────────── - ws = wb.create_sheet("PC→PLC (Write)") - set_col_widths(ws, {"A":3.7,"B":8,"C":14,"D":28,"E":10,"F":14,"G":8,"H":36,"I":28,"J":22}) - write_banner(ws, 2, 2, 10, - "PC → PLC 신호 (PC Write)", - "PC(Aurora)가 PLC로 보내는 요청·결과·보정값") - HDR = ["No","Seq/구분","신호명","방향","디바이스(제안)","Type","의미 / 트리거","응답·완료","비고"] - write_header_row(ws, 4, 2, HDR) - write_rows = [ - ["0x00","Status","PC_LIVE_STATUS","PC→PLC","M70000(제안)","BIT","PC Alive","","Watchdog"], - ["0x01","Status","PC_AUTO_STATUS","PC→PLC","M70001","BIT","Auto 상태","","Enter시 true"], - ["0x02","Status","PC_AUTO_COMPLETE","PC→PLC","M70002","BIT","Auto 완료","",""], - ["0x03","Status","PC_MANUAL_COMPLETE","PC→PLC","M70003","BIT","Manual 완료","",""], - ["0x04","Alarm","PC_LIGHT_ALARM_STATUS","PC→PLC","M70004","BIT","경알람","",""], - ["0x05","Alarm","PC_HEAVY_ALARM_STATUS","PC→PLC","M70005","BIT","중알람","",""], - ["0x06","Status","PC_DOOR_INTERLOCK","PC→PLC","M70006","BIT","Door 인터락","",""], - ["0x07","Status","PC_EMO_STATUS","PC→PLC","M70007","BIT","EMO","",""], - ["0x08","Process","PC_PAGE_CHANGE_COMPLETE","PC→PLC","M70008","BIT","페이지 확정 ACK","","PageNo 일치시 ON"], - ["0x09","Process","PC_RECIPE_CHANGE_COMPLETE","PC→PLC","M70009","BIT","레시피 변경 완료(미감시)","","260618"], - ["0x0F","Process","PC_WELD_READY_ACK","PC→PLC","M70015","BIT","Resume ACK/run","","bit15,260621"], - ["0x10","Process","PC_WELD_TRIGGER_ACK","PC→PLC","M70016","BIT","용접 트리거 ACK","",""], - ["0x11","Status","PC_WELD_BUSY","PC→PLC","M70017","BIT","Laser On 표시","","260626"], - ["0x12","Process","PC_WELD_COMPLETE","PC→PLC","M70018","BIT","용접 완료","",""], - ["0x14","Process","PC_WELD_NG_JUDGE","PC→PLC","M70020","BIT","용접 NG 판정","",""], - ["0x25","Request","PC_RMS_PARAMETER_READ_REQUEST_ACK","PC→PLC","M70037","BIT","RMS read ACK","",""], - ["D0x00","Info","PC_ERROR_CODE","PC→PLC","D70000(제안)","INT","에러코드 에코","",""], - ["D0x01","Info","PC_PAGE_NO","PC→PLC","D70001","INT","페이지 에코","",""], - ["D0x02","Info","PC_RECIPE_NO","PC→PLC","D70002","INT","레시피 에코","","260618"], - ["D0x08","Process","PC_WELD_OFFSET_X","PC→PLC","D70008","INT","용접 보정 X","",""], - ["D0x0A","Process","PC_WELD_OFFSET_Y","PC→PLC","D70010","INT","용접 보정 Y","",""], - ["D0x0C","Process","PC_DISPLACEMENT1_MEASUREMENT","PC→PLC","D70012","INT","변위 측정1","",""], - ["D0x0E","Process","PC_DISPLACEMENT2_MEASUREMENT","PC→PLC","D70014","INT","변위 측정2","",""], - ["D0x14~","Info","PC_CELL_ID_01~10","PC→PLC","D70020~","INT(ASCII)","Cell ID 에코","",""], - ["D0x1E~","Info","PC_LOT_ID_01~08","PC→PLC","D70030~","INT(ASCII)","Lot ID 에코","",""], - ["D0x28~","Info","PC_FDC_PAGE1~3_POWER/VELOCITY","PC→PLC","D70040~","INT","FDC 파워/속도","",""], - ["D0x3C~","Info","PC_RMS_ALLOC_START~END","PC→PLC","D70060~97","INT","RMS 할당","",""], - ] - write_data_rows(ws, 5, 2, write_rows, center_cols={0,3,5}) - n = len(write_rows) - group_merge(ws, 3, 5, n, [r[1] for r in write_rows]) - ws.merge_cells(f"E5:E{4+n}") - - # ── PLC→PC (Read) ────────────────────────────── - ws = wb.create_sheet("PLC→PC (Read)") - set_col_widths(ws, {"A":3.7,"B":8,"C":14,"D":28,"E":10,"F":14,"G":8,"H":36,"I":28,"J":22}) - write_banner(ws, 2, 2, 10, - "PLC → PC 신호 (PC Read)", - "PLC가 PC로 보내는 요청·상태·완료") - write_header_row(ws, 4, 2, HDR) - read_rows = [ - ["0x00","Status","PLC_LIVE_STATUS","PLC→PC","M70500(제안)","BIT","PLC Alive","Watchdog",""], - ["0x01","Status","PLC_AUTO_STATUS","PLC→PC","M70501","BIT","Auto 상태","",""], - ["0x02","Request","PLC_AUTO_REQ","PLC→PC","M70502","BIT","Auto 요청","PC_AUTO_STATUS",""], - ["0x03","Request","PLC_MANUAL_REQ","PLC→PC","M70503","BIT","Manual 요청","",""], - ["0x04","Alarm","PLC_LIGHT_ALARM_STATUS","PLC→PC","M70504","BIT","경알람","",""], - ["0x05","Alarm","PLC_HEAVY_ALARM_STATUS","PLC→PC","M70505","BIT","중알람","시퀀스 정지",""], - ["0x06","Status","PLC_DOOR_INTERLOCK","PLC→PC","M70506","BIT","Door","인터락",""], - ["0x07","Status","PLC_EMO_STATUS","PLC→PC","M70507","BIT","EMO","인터락",""], - ["0x08","Request","PLC_PAGE_CHANGE_REQ","PLC→PC","M70508","BIT","단일 게이트 트리거","Page+Recipe 확정",""], - ["0x09","Request","PLC_SCOUT_ENABLE","PLC→PC","M70509","BIT","Scout Enable","","260622"], - ["0x0F","Request","PLC_WELD_READY_REQ","PLC→PC","M70515","BIT","Weld_01 Ready→Resume","","bit15,260621"], - ["0x10","Request","PLC_WELD_TRIGGER_REQ","PLC→PC","M70516","BIT","용접 발진 요청","READY_ACK/BUSY",""], - ["0x11","Status","PLC_WELD_WAIT","PLC→PC","M70517","BIT","용접 대기","",""], - ["0x12","Process","PLC_WELD_COMPLETE_ACK","PLC→PC","M70518","BIT","용접 완료 ACK","",""], - ["0x1E","Alarm","PLC_ALARM_RESET","PLC→PC","M70530","BIT","알람 리셋","",""], - ["0x25","Request","PLC_RMS_PARAMETER_READ_REQUEST","PLC→PC","M70537","BIT","RMS read 요청","ACK",""], - ["D0x00","Info","PLC_ERROR_CODE","PLC→PC","D70500(제안)","INT","에러코드","",""], - ["D0x01","Info","PLC_PAGE_NO","PLC→PC","D70501","INT","페이지(1-base)","3회 검증",""], - ["D0x02","Info","PLC_RECIPE_NO","PLC→PC","D70502","INT","레시피(11/21/22/31/32)","","260618"], - ["D0x03","Info","PLC_CURRENT_SLOT_NO","PLC→PC","D70503","INT","현재 슬롯","EL/CLEAN",""], - ["D0x0A","Process","HEAD_THETA_POSITION","PLC→PC","D70510","INT","Laser1 Head Theta","발진 인터락",""], - ["D0x14~","Info","PLC_CELL_ID_01~10","PLC→PC","D70520~","INT(ASCII)","Cell ID","",""], - ["D0x1E~","Info","PLC_LOT_ID_01~08","PLC→PC","D70530~","INT(ASCII)","Lot ID","",""], - ] - write_data_rows(ws, 5, 2, read_rows, center_cols={0,3,5}) - n = len(read_rows) - group_merge(ws, 3, 5, n, [r[1] for r in read_rows]) - ws.merge_cells(f"E5:E{4+n}") - - # ── 핸드셰이크 시퀀스 ───────────────────────── - ws = wb.create_sheet("핸드셰이크 시퀀스") - set_col_widths(ws, {"A":3.7,"B":6,"C":16,"D":6,"E":8,"F":48,"G":36,"H":40}) - write_banner(ws, 2, 2, 8, - "PLC ↔ PC 핸드셰이크 시퀀스 (Seq별)", - "요청 → 처리 → 완료/응답 흐름 │ PtoP Welder 단일 게이트(PLC_PAGE_CHANGE_REQ) 기준") - write_header_row(ws, 4, 2, ["No","Seq","Step","주체","동작 / 신호","디바이스(제안)","비고"]) - hs = [ - [1,"PageGate",1,"PLC","Page Change 요청(단일 게이트)","PLC_PAGE_CHANGE_REQ(M70508) Set","Page+Recipe 확정 트리거"], - [2,"PageGate",2,"PC","Recipe 확정/전환","PLC_RECIPE_NO(D70502)→ActivateRecipe→PC_RECIPE_NO(D70002) 에코","0/동일이면 전환 생략"], - [3,"PageGate",3,"PC","Page 3회 검증·확정","PLC_PAGE_NO(D70501) 3회→PC_PAGE_NO 에코→PC_PAGE_CHANGE_COMPLETE(M70008) Set","200ms×3"], - [4,"PageGate",4,"PC","용접 리스트 업로드","레이어 선택 + SeqUploadWeldingList","-"], - [5,"Weld",1,"PLC","발진 요청","PLC_WELD_TRIGGER_REQ(M70516) Set","PreScout(M70509) 옵션"], - [6,"Weld",2,"PC","발진 ACK · BUSY","PC_WELD_TRIGGER_ACK(M70016) Set → PC_WELD_BUSY(M70017) ON","HeadTheta(D70510) 인터락"], - [7,"Weld",3,"PC","실제 발진(Gate ON/OFF)","Scanner.ExecuteList → Gate ON/OFF","laserEmissionGateDelay 15ms"], - [8,"Weld",4,"PC","완료 통지","PC_WELD_BUSY OFF → PC_WELD_COMPLETE(M70018) Set","PostScout(M70509) 옵션"], - [9,"Weld",5,"양측","완료 ACK · Clear","PLC_WELD_COMPLETE_ACK(M70518) → TRIGGER_ACK OFF","루프백(PLC_PAGE_CHANGE_REQ) 대기"], - [10,"Resume",1,"PLC","Weld_01 Ready → Resume 요청","PLC_WELD_READY_REQ(M70515) Set","bit15, Auto→Manual+Resume(가변용접)"], - [11,"Resume",2,"PC","Resume ACK / run","PC_WELD_READY_ACK(M70015) Set","Resume 시 READY_ACK OFF"], - [12,"Interlock",1,"PLC","Door/EMO/Heavy 상태 공유","PLC_DOOR(M70506)/EMO(M70507)/HEAVY(M70505)","이상 시 시퀀스 정지"], - [13,"Status",1,"양측","Alive Watchdog 토글","PC_LIVE(M70000) ↔ PLC_LIVE(M70500)","단절 시 안전정지"], - [14,"Alarm",1,"PC","PC 알람 통지","PC_LIGHT_ALARM(M70004)/HEAVY_ALARM(M70005) Set","중알람 시 시퀀스 정지"], - ] - write_data_rows(ws, 5, 2, hs, center_cols={0,2,3}) - group_merge(ws, 3, 5, len(hs), [r[1] for r in hs]) - - os.makedirs(os.path.dirname(OUT), exist_ok=True) - wb.save(OUT); print("✓ PLC-PC:", OUT) - - -# ══════════════════════════════════════════════════════ -# 2. 모션축·IO 맵 정의서 -# 탭: 통신·제어 구성 | 모션축 정의(ACS) | I-O 맵(DI/DO) -# ══════════════════════════════════════════════════════ -def build_motio(): - wb = make_workbook() - OUT = OUT_DIR + "IO_DB설계/모션축_IO맵_정의서.xlsx" - - # ── 통신·제어 구성 ───────────────────────────── - ws = wb.create_sheet("통신·제어 구성") - set_col_widths(ws, {"A":4.4,"B":16,"C":24.8,"D":26,"E":20,"F":22,"G":34}) - write_banner(ws, 2, 2, 7, - "PtoP Welder(가접용접기) 통신 · 제어 구성 (PC / Aurora)", - "근거: EquipmentSetup.RegisterDevices() / PAIX_PTOP.cs / architecture.md §4 │ 주소·수량=제안") - write_header_row(ws, 4, 2, ["구분","대상","컨트롤러 / 디바이스","통신 / 버스","수량·범위","비고"]) - write_data_rows(ws, 5, 2, [ - ["PLC통신","외부 신호 제어","Mitsubishi Melsec","MX Component","1","ePLCNetType.MXComponent"], - ["I/O","디지털 IO","(제안) 보드타입 런타임 설정 — IOUnitConfig.BoardType 확인 필요","필드버스","DI/DO","PAIX_PTOP:IODevice"], - ["Laser","Core/Ring 레이저","IO Gate(TruPulse nano)","DO 게이트","2","ExecuteWelding Gate"], - ["Scanner","레이저 스캐너","RTC LaserScanner","RTC","1","Scanner.ExecuteList"], - ["모션(Servo)","X/Y 축","ACS SPiiPlus","EtherCAT","2축 (제안)","AuroraACS"], - ["모션(Servo)","Z 축","(제안) AuroraMotionBoard — 보드타입 확인 필요","보드","1축 (제안)","AuroraMotionBoard"], - ["Vision","카메라/측정","MIL 기반","-","-","AuroraVision(현재 미사용)"], - ["상/하위(MES)","호스트 연동","Stream(LBAD/RPC)","TCP","옵션","UseStream 시"], - ], center_cols={0,4}) - - # ── 모션축 정의(ACS) ──────────────────────────── - ws = wb.create_sheet("모션축 정의(ACS)") - set_col_widths(ws, {"A":4.4,"B":7,"C":12,"D":18,"E":22,"F":8,"G":12,"H":10,"I":10,"J":10,"K":10,"L":20}) - write_banner(ws, 2, 2, 12, - "PtoP Welder(가접용접기) 모션축 구성표 (ACS · MotionBoard) — 제안", - "각 축 Init / 단축·동기축 / Jog·Relative·Absolute │ 행정·속도·Home은 모듈 소스 미보유 → (제안)") - write_header_row(ws, 4, 2, - ["Axis","축 명(논리)","용도","컨트롤러/통신","구동","행정/범위","최대속도","Home 방식","Soft Limit","동기/단축","비고"]) - write_data_rows(ws, 5, 2, [ - ["0","X","셀 위치 X","ACS SPiiPlus/EtherCAT","Servo","(제안)","(제안)","(제안)","(제안)","단축",""], - ["1","Y","셀 위치 Y","ACS SPiiPlus/EtherCAT","Servo","(제안)","(제안)","(제안)","(제안)","단축",""], - ["2","Z","포커스/높이","(제안) AuroraMotionBoard","Servo","(제안)","(제안)","(제안)","(제안)","단축",""], - ["-","Scanner θ/XY","빔 편향(갈바노)","RTC LaserScanner","Galvano","List Jump/Mark","-","-","보정테이블","-",""], - ], center_cols={0,1,4,5,6,7,8,9}) - ws.cell(12, 3).value = "※ ACS = PC가 EtherCAT으로 직접 제어하는 Servo 축(X/Y). Z는 AuroraMotionBoard(보드타입 미확정), Scanner θ/XY는 RTC 갈바노. 행정/속도/Home 미확정." - ws.cell(12, 3).font = Font(name="맑은 고딕", size=9, italic=True) - - # ── I-O 맵 (DI/DO) ─────────────────────────────── - ws = wb.create_sheet("I-O 맵(DI-DO)") - set_col_widths(ws, {"A":4.4,"B":6,"C":30,"D":6,"E":10,"F":10,"G":8,"H":36,"I":20}) - write_banner(ws, 2, 2, 9, - "PtoP Welder(가접용접기) I/O 맵 (DI/DO) — 근거: PAIX_PTOP.cs ePrismaticDI/DOAddress · 보드 벤더 미확정", - "근거: PAIX_PTOP.cs ePrismaticDIAddress / ePrismaticDOAddress · DI 9~23 / DO 9~17") - write_header_row(ws, 4, 2, ["No","신호명","Type","권장 모듈","슬롯/CH","Active","설명/인터락","비고"]) - raw_io = [ - (9,"CoreLaser_Laser_Ready","DI","DI","High","Core 레이저 Ready"), - (10,"CoreLaser_Error_State","DI","DI","High","Core 레이저 에러"), - (11,"CoreLaser_Laser_Output_State","DI","DI","High","Core 발진 출력 상태"), - (12,"CoreLaser_Control_Status","DI","DI","High","Core 제어 상태"), - (13,"RingLaser_Laser_Ready","DI","DI","High","Ring 레이저 Ready"), - (14,"RingLaser_Error_State","DI","DI","High","Ring 레이저 에러"), - (15,"RingLaser_Laser_Output_State","DI","DI","High","Ring 발진 출력 상태"), - (23,"RingLaser_Control_Status","DI","DI","High","Ring 제어 상태"), - (9,"CoreLaser_Control","DO","DO","High","Core 레이저 게이트(발진)"), - (10,"CoreLaser_ErrorClearing","DO","DO","High","Core 에러 클리어"), - (13,"RingLaser_Control","DO","DO","High","Ring 레이저 게이트(발진)"), - (14,"RingLaser_ErrorClearing","DO","DO","High","Ring 에러 클리어"), - (17,"EX_Red_Control","DO","DO","High","EX Red 표시등 제어"), - ] - io_rows = [[i+1, name, typ, mod, f"{typ} Ch{ch}", act, desc, ""] - for i,(ch,name,typ,mod,act,desc) in enumerate(raw_io)] - write_data_rows(ws, 5, 2, io_rows, center_cols={0,2,3,4,5}) - - os.makedirs(os.path.dirname(OUT), exist_ok=True) - wb.save(OUT); print("✓ 모션축·IO:", OUT) - - -# ══════════════════════════════════════════════════════ -# 3. 기능명세서 -# 탭: OverView | MainView | RecipeView | ManualView | -# DeviceView | SettingView | VisionView | Sequence 흐름 -# ══════════════════════════════════════════════════════ -def build_funcspec(): - wb = make_workbook() - OUT = OUT_DIR + "UIUX_기능설계/기능명세서.xlsx" - - # FUNC 계열은 배경 없이 thin border만 사용 - tb = lambda: FUNC_DATA_BORDER - - # ── OverView ──────────────────────────────────── - ws = wb.create_sheet("OverView") - set_col_widths(ws, {"A":4.1,"B":7.8,"C":66,"D":18.2,"E":19.3}) - set_row_height(ws, 2, 43.5) - c = ws.cell(2, 2, "PtoP Welder(가접용접기) SW 기능명세서") - _apply(c, FUNC_BANNER_FONT, border=_border("medium","medium","medium","medium"), - alignment=Alignment(horizontal="center",vertical="center",wrap_text=True)) - ws.merge_cells("B2:E2") - # FUNC 헤더: 배경 없음(None), thin border - write_header_row(ws, 4, 2, ["no.","Content"], font=FUNC_HEADER_FONT, fill=None) - ov_items = [ - "운영 SW는 LG PRI의 Aurora 플랫폼으로 개발", - "운영 환경 : Windows 11, .NET Framework", - "개발 환경 : Windows 11, Visual Studio", - "설비 : PtoP Welder(가접용접기) — 셀 P2P 레이저 가접(Tack) 용접", - "모션 : ACS SPiiPlus(X/Y, EtherCAT) + AuroraMotionBoard(Z, 보드타입 미확정), 빔 편향 = RTC 갈바노 스캐너", - "레이저 : Core / Ring 2계통, IO Gate(TruPulse nano) 발진", - "PLC : Mitsubishi MELSEC / MX Component, 단일 게이트(PAGE_REQ) 핸드셰이크", - "비전 : MIL 기반(현재 AuroraVision 미사용)", - ] - for i, txt in enumerate(ov_items): - r = 5 + i - ws.cell(r, 2, i+1).font = FUNC_DATA_FONT - ws.cell(r, 2).border = tb() - ws.cell(r, 2).alignment = Alignment(horizontal="center", vertical="center") - ws.cell(r, 3, txt).font = FUNC_DATA_FONT - ws.cell(r, 3).border = tb() - ws.cell(r, 3).alignment = Alignment(horizontal="left", vertical="center", wrap_text=True) - ws.merge_cells(f"C{r}:E{r}") - - # ── View 시트 공통 헬퍼 ────────────────────────── - # 헤더: Update|Funtion Area|Funtion Name|NO|Sub|Content - VIEW_HDR = ["Update","Funtion Area","Funtion Name","NO","Sub","Content"] - def make_view(name, banner_text, rows): - ws = wb.create_sheet(name) - set_col_widths(ws, {"A":4,"B":14,"C":16,"D":24,"E":6,"F":14,"G":48}) - set_row_height(ws, 3, 28) - ws.cell(3, 7, banner_text).font = FUNC_DATA_FONT - ws.cell(3, 7).alignment = Alignment(horizontal="left", vertical="center") - set_row_height(ws, 5, 20) - for j, h in enumerate(VIEW_HDR): - c = ws.cell(5, 2+j, h) - c.font = FUNC_HEADER_FONT - c.border = tb() - c.alignment = Alignment(horizontal="center", vertical="center") - for i, row in enumerate(rows): - r = 6 + i - vals = [TODAY] + row - for j, v in enumerate(vals): - c = ws.cell(r, 2+j, v) - c.font = FUNC_DATA_FONT - c.border = tb() - c.alignment = Alignment( - horizontal="center" if j in {0,3} else "left", - vertical="center", wrap_text=True) - - make_view("MainView","다음은 Main 화면에서 보여야 하는 기능이다.",[ - ["운전","StartSequence/Stop", 1,"SeqAutoRunPTOP", "자동운전 시작/정지"], - ["상태","UpdatePageNum", 2,"EVENT_AUTO_RUN_UPDATE_PAGENUM","현재 페이지 표시"], - ["상태","WorkingPosition", 3,"eWorkingPosition", "용접 진행 위치 표시"], - ["운전","Auto→Manual+Resume", 4,"bit15(PLC_WELD_READY_REQ)", "Resume(가변용접) 기능"], - ["표시","ScannerCanvasCtrlTeaching", 5,"레이어/오브젝트", "스캐너 캔버스"], - ]) - make_view("RecipeView","다음은 Recipe 화면에서 보여야 하는 기능이다.",[ - ["레시피","ActivateRecipe", 1,"RecipeManager", "레시피 선택/활성"], - ["레시피","RecipeChangeHistory", 2,"RchHandler", "변경 이력"], - ["모델", "UCModel", 3,"EquipmentSpecificModel_PTOP","모델 편집"], - ]) - make_view("ManualView","다음은 Manual 화면에서 보여야 하는 기능이다.",[ - ["Manual", "ScannerOperation", 1,"ScannerOperationView","스캐너 수동 조작(발진/Jump/Mark)"], - ["Manual", "ModelFinder", 2,"ModelFinderView", "모델 파인더"], - ["Calibration","ScannerCalibration",3,"(제안)", "스캐너 보정"], - ["Calibration","PixelResolution", 4,"(제안)", "픽셀 해상도"], - ]) - make_view("DeviceView","다음은 Device 화면에서 보여야 하는 기능이다.",[ - ["Device", "DeviceSettingView", 1,"LEVEL3", "디바이스 설정(활성/비활성)"], - ["Monitoring","PLCBitMonitoring", 2,"ePLCDevice.M","PLC 비트 모니터"], - ["Monitoring","PLCWordMonitoring", 3,"ePLCDevice.D","PLC 워드 모니터"], - ["Monitoring","IOInterfaceView", 4,"IODevice", "IO 인터페이스"], - ]) - make_view("SettingView","다음은 Setting 화면에서 보여야 하는 기능이다.",[ - ["Setting","Equipment", 1,"LEVEL1", "장비 설정"], - ["Setting","Log", 2,"-", "로그 설정"], - ["Setting","AutoBackup", 3,"-", "자동 백업"], - ["Alarm", "History/Desc", 4,"-", "알람 이력·설명"], - ["Stream", "ServiceSettingView",5,"UseStream","Stream(상/하위) 사용 시"], - ]) - make_view("VisionView","다음은 Vision 화면에서 보여야 하는 기능이다.",[ - ["Vision","(해당없음)",1,"AuroraVision 미사용","MIL 기반 — 현재 미사용(제안)"], - ]) - - # ── Sequence 흐름: Update|Funtion Area|Processing Name|NO|Content - ws = wb.create_sheet("Sequence 흐름") - set_col_widths(ws, {"A":4,"B":14,"C":16,"D":24,"E":6,"F":60}) - SEQ_HDR = ["Update","Funtion Area","Processing Name","NO","Content"] - set_row_height(ws, 5, 20) - for j,h in enumerate(SEQ_HDR): - c = ws.cell(5, 2+j, h) - c.font = FUNC_HEADER_FONT; c.border = tb() - c.alignment = Alignment(horizontal="center",vertical="center") - seq_data = [ - ["AutoRun","PAGE_REQ Gate", 1,"PLC_PAGE_CHANGE_REQ(M70508) 단일 게이트 트리거"], - ["AutoRun","Recipe 확정", 2,"PLC_RECIPE_NO→ActivateRecipe→PC_RECIPE_NO 에코(0/동일 생략)"], - ["AutoRun","Page 확정", 3,"PLC_PAGE_NO 3회 검증→PC_PAGE_CHANGE_COMPLETE"], - ["AutoRun","List Upload", 4,"레이어 선택 + SeqUploadWeldingList"], - ["AutoRun","발진 요청", 5,"PLC_WELD_TRIGGER_REQ→PC_WELD_TRIGGER_ACK/BUSY(HeadTheta 인터락)"], - ["AutoRun","발진", 6,"Gate ON(15ms)→Scanner.ExecuteList→Gate OFF"], - ["AutoRun","완료", 7,"PC_WELD_COMPLETE→PLC_WELD_COMPLETE_ACK"], - ["AutoRun","루프백", 8,"CheckCycleStop→PAGE_REQ 대기(Resume 시 READY_ACK OFF)"], - ] - for i, row in enumerate(seq_data): - r = 6 + i - vals = [TODAY] + row - for j,v in enumerate(vals): - c = ws.cell(r, 2+j, v) - c.font = FUNC_DATA_FONT; c.border = tb() - c.alignment = Alignment(horizontal="center" if j in {0,3} else "left", - vertical="center", wrap_text=True) - - os.makedirs(os.path.dirname(OUT), exist_ok=True) - wb.save(OUT); print("✓ 기능명세서:", OUT) - - -# ══════════════════════════════════════════════════════ -# 4. TactTime 산정서 -# 탭: PLC TactTime | PC TactTime -# ══════════════════════════════════════════════════════ -def build_tact(): - wb = make_workbook() - OUT = OUT_DIR + "시퀀스_인터록/TactTime_산정서.xlsx" - - def tact_cell(ws, r, c, v, align="center"): - cell = ws.cell(r, c, v) - cell.font = TACT_FONT; cell.border = TACT_BORDER - cell.alignment = Alignment(horizontal=align, vertical="center", wrap_text=True) - return cell - - # ── PLC TactTime (미입수) ────────────────────── - ws = wb.create_sheet("PLC TactTime") - set_col_widths(ws, {"B":18,"C":19.5,"D":49.6,"E":10,"F":10.8}) - set_row_height(ws, 3, 53) - tact_cell(ws, 3, 2, "PLC Main 동작 (PtoP Welder) — 미입수") - ws.merge_cells("B3:E3") - write_header_row(ws, 4, 2, ["공정","Unit","단위동작","T/T"], font=TACT_FONT, fill=None) - set_row_height(ws, 4, 22) - set_row_height(ws, 5, 40) - tact_cell(ws, 5, 2, "(미입수)", "center") - tact_cell(ws, 5, 3, "PLC 시퀀스 사양 입수 후 작성", "left") - tact_cell(ws, 5, 4, "셀 로딩 / 언로딩 / 페이지 인덱싱 T/T — PLC 측 단위동작 미보유(제안)", "left") - tact_cell(ws, 5, 5, "미입수", "center") - - # ── PC TactTime ──────────────────────────────── - ws = wb.create_sheet("PC TactTime") - set_col_widths(ws, {"A":11.7,"B":18,"C":38.1,"D":75.8,"E":8,"F":10.9,"G":12.2,"H":42,"I":12,"J":13}) - set_row_height(ws, 3, 53) - tact_cell(ws, 3, 2, "Main 동작 (PtoP Welder · 자동, 값=제안 / 출처: SeqAutoRunPTOP.cs)", "left") - ws.merge_cells("B3:E3") - tact_cell(ws, 3, 8, "구간 합계") - ws.merge_cells("H3:J3") - # 헤더 행 높이 - set_row_height(ws, 4, 22) - for col, h in zip([2,3,4,5], ["공정","Unit","단위동작","T/T"]): - tact_cell(ws, 4, col, h) - for col, h in zip([8,9,10], ["Working Process","상세합계","기준/참조합계"]): - tact_cell(ws, 4, col, h) - - L = [ - ("Page/Recipe 게이트","핸드셰이크","Page Change 요청 대기","가변"), - ("Page/Recipe 게이트","핸드셰이크","Recipe 확정/전환","~0~수백"), - ("Page/Recipe 게이트","핸드셰이크","Page 3회 검증 (200ms×3)","~600"), - ("Page/Recipe 게이트","핸드셰이크","용접리스트 업로드","가변"), - ("발진 준비","WeldingStart","발진 요청 대기","가변"), - ("발진 준비","WeldingStart","준비 응답 WaitWeldingStart(200+5)","~205"), - ("발진","ExecuteWelding","Gate ON delay(laserEmissionGateDelayMs)","15"), - ("발진","ExecuteWelding","실제 발진 Scanner.ExecuteList","~285"), - ("발진","ExecuteWelding","Gate OFF + BUSY OFF","~50"), - ("발진","ExecuteWelding","Jump+Correction 복귀 Thread.Sleep(500)","~500"), - ("완료","WeldComplete","완료비트 송신 WriteWeldComplete(50+5)","~55"), - ("옵션","Scout","Pre/Post Scout (M70509 ON 시)","+100/회"), - ] - R = [ - ("Page/Recipe 게이트","가변(폴링 10ms, timeout 60s)","-"), - ("발진 준비","~205",""), - ("발진(1발 기준)","~850 (15+285+50+500)",""), - ("완료","~55",""), - ("Scout(옵션)","+100/회",""), - ("1 사이클(가변 제외)","≈1110+","제안"), - ] - for i, (grp, unit, action, tt) in enumerate(L): - r = 5 + i - set_row_height(ws, r, 30) - tact_cell(ws, r, 2, grp, "left") - tact_cell(ws, r, 3, unit, "left") - tact_cell(ws, r, 4, action, "left") - tact_cell(ws, r, 5, tt, "center") - for i, (proc, detail, ref_) in enumerate(R): - r = 5 + i - tact_cell(ws, r, 8, proc, "left") - tact_cell(ws, r, 9, detail, "center") - tact_cell(ws, r, 10, ref_, "center") - # 공정 그룹 병합 - group_merge(ws, 2, 5, len(L), [r[0] for r in L]) - group_merge(ws, 3, 5, len(L), [r[0]+"|"+r[1] for r in L]) - - os.makedirs(os.path.dirname(OUT), exist_ok=True) - wb.save(OUT); print("✓ TactTime:", OUT) - - -# ══════════════════════════════════════════════════════ -if __name__ == "__main__": - build_plcpc() - build_motio() - build_funcspec() - build_tact() - print("\n✅ 02.설계 xlsx 4종 재생산 완료 (ref 파일 불필요).") diff --git a/.claude/skills/ubisam-deliverables/references/xlsxfill.py b/.claude/skills/ubisam-deliverables/references/xlsxfill.py deleted file mode 100644 index 1eb6371..0000000 --- a/.claude/skills/ubisam-deliverables/references/xlsxfill.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- coding: utf-8 -*- -""" -xlsxfill.py — LG PRI 표준 양식 xlsx 헬퍼 (ref 파일 불필요 · 완전 독립) - -스타일 상수는 LG PRI 표준 양식에서 추출한 값으로 하드코딩됨(원본 ref 파일에 의존하지 않는다). -모든 파일 구조(배너·헤더·데이터·그룹병합)를 openpyxl만으로 재현한다. - -사용법: - import sys - sys.path.insert(0, os.path.dirname(__file__)) - from xlsxfill import ( - make_workbook, set_col_widths, set_row_height, - write_banner, write_header_row, write_data_rows, group_merge, - BANNER_FONT, BANNER_FILL, HEADER_FONT, HEADER_FILL, - DATA_FONT, DATA_FILL_ODD, DATA_FILL_EVEN, - FUNC_BANNER_FONT, FUNC_HEADER_FONT, FUNC_DATA_FONT, - TACT_FONT, TACT_BORDER, _apply, _border, - ) - -전제조건: Python 3.9+, openpyxl >= 3.1 -실행(저장소 루트에서, 맨 파일명 금지 — 셸 cwd는 호출마다 초기화된다): - PYTHONUTF8=1 py .claude/skills/ubisam-deliverables/references/build_02설계_xlsx.py -""" -import openpyxl -from openpyxl import Workbook -from openpyxl.styles import Font, PatternFill, Border, Side, Alignment, GradientFill -from openpyxl.utils import get_column_letter -from openpyxl.utils.cell import range_boundaries - -# ───────────────────────────────────────────── -# 스타일 상수 (ref 파일 직접 추출값) -# ───────────────────────────────────────────── -_F = Font -_P = PatternFill -_B = Border -_S = Side -_A = Alignment - -def _border(left=None, right=None, top=None, bottom=None): - def s(v): return _S(border_style=v) if v else _S() - return _B(left=s(left), right=s(right), top=s(top), bottom=s(bottom)) - -# 배너 행 (B2) — 진네이비 배경, 흰 굵은 글자 -BANNER_FONT = _F(name="맑은 고딕", size=13, bold=True, color="FFFFFFFF") -BANNER_FILL = _P("solid", fgColor="FF1F4E78") -BANNER_BORDER = _border("medium","medium","medium","medium") -BANNER_ALIGN = _A(horizontal="center", vertical="center", wrap_text=True) - -# 부제 행 (B3) — 테두리만 -SUBBANNER_FONT = _F(name="맑은 고딕", size=9) -SUBBANNER_BORDER = _border("medium","medium",None,None) -SUBBANNER_ALIGN = _A(horizontal="left", vertical="center", wrap_text=True) - -# 헤더 행 (B4/B5 등) — 파랑 배경, 흰 굵은 글자 -HEADER_FONT = _F(name="맑은 고딕", size=11, bold=True, color="FFFFFFFF") -HEADER_FILL = _P("solid", fgColor="FF2E75B6") -HEADER_BORDER_FIRST = _border("medium","thin","thin","thin") -HEADER_BORDER_MID = _border("thin","thin","thin","thin") -HEADER_BORDER_LAST = _border("thin","medium","thin","thin") -HEADER_ALIGN = _A(horizontal="center", vertical="center", wrap_text=True) - -# 데이터 행 — 교대 배경(연파랑) + 흰 배경 -DATA_FONT = _F(name="맑은 고딕", size=10) -DATA_FILL_ODD = _P("solid", fgColor="FFDDEBF7") # 연파랑 (홀수행) -DATA_FILL_EVEN = _P("solid", fgColor="FFFFFFFF") # 흰색 (짝수행) -DATA_BORDER_FIRST = _border("medium","thin","thin","thin") -DATA_BORDER_MID = _border("thin","thin","thin","thin") -DATA_BORDER_LAST = _border("thin","medium","thin","thin") -DATA_ALIGN_L = _A(horizontal="left", vertical="center", wrap_text=True) -DATA_ALIGN_C = _A(horizontal="center", vertical="center", wrap_text=True) - -# 기능명세서 전용 스타일 (FUNC ref: 맑은 고딕, 14pt 배너) -FUNC_BANNER_FONT = _F(name="맑은 고딕", size=14, bold=True) -FUNC_HEADER_FONT = _F(name="맑은 고딕", size=11, bold=True) -FUNC_HEADER_BORDER = _border("thin","thin","thin","thin") -FUNC_DATA_FONT = _F(name="맑은 고딕", size=11) -FUNC_DATA_BORDER = _border("thin","thin","thin","thin") -FUNC_DATA_ALIGN = _A(horizontal="left", vertical="center", wrap_text=True) - -# TactTime 전용 (단순 thin 테두리, 색상 없음) -TACT_FONT = _F(name="맑은 고딕", size=11) -TACT_BORDER = _border("thin","thin","thin","thin") -TACT_ALIGN = _A(horizontal="center", vertical="center", wrap_text=True) -TACT_ALIGN_L= _A(horizontal="left", vertical="center", wrap_text=True) - - -# ───────────────────────────────────────────── -# 헬퍼 함수 -# ───────────────────────────────────────────── - -_UNSET = object() # write_header_row fill/font 기본값 sentinel - - -def make_workbook(): - wb = Workbook() - wb.remove(wb.active) # 기본 Sheet 제거 - return wb - - -def set_col_widths(ws, widths: dict): - """widths: {'A':4.4, 'B':16.0, ...}""" - for col, w in widths.items(): - ws.column_dimensions[col].width = w - - -def set_row_height(ws, row, height): - ws.row_dimensions[row].height = height - - -def _apply(cell, font=None, fill=None, border=None, alignment=None): - if font: cell.font = font - if fill: cell.fill = fill - if border: cell.border = border - if alignment: cell.alignment = alignment - - -def write_banner(ws, row, col_start, col_end, title, subtitle=None, - banner_h=26, sub_h=24): - """배너 2행(제목+부제)을 쓰고 병합한다.""" - set_row_height(ws, row, banner_h) - # 제목 - c = ws.cell(row, col_start, title) - _apply(c, BANNER_FONT, BANNER_FILL, BANNER_BORDER, BANNER_ALIGN) - L = get_column_letter - if col_end > col_start: - ws.merge_cells(f"{L(col_start)}{row}:{L(col_end)}{row}") - # 우측 셀 border 유지 - ws.cell(row, col_end).border = _border(right="medium", top="medium", bottom="medium") - if subtitle is not None: - set_row_height(ws, row+1, sub_h) - c2 = ws.cell(row+1, col_start, subtitle) - _apply(c2, SUBBANNER_FONT, border=SUBBANNER_BORDER, alignment=SUBBANNER_ALIGN) - if col_end > col_start: - ws.merge_cells(f"{L(col_start)}{row+1}:{L(col_end)}{row+1}") - ws.cell(row+1, col_end).border = _border(right="medium") - - -def write_header_row(ws, row, col_start, headers, height=22, - font=_UNSET, fill=_UNSET): - """헤더 행 작성. 첫/마지막 열 medium 테두리. - fill=None 을 넘기면 배경 없음(흰색). 생략하면 HEADER_FILL(파랑) 적용. - font=None 을 넘기면 폰트 미설정. 생략하면 HEADER_FONT 적용. - """ - set_row_height(ws, row, height) - _font = HEADER_FONT if font is _UNSET else font - _fill = HEADER_FILL if fill is _UNSET else fill - n = len(headers) - for i, h in enumerate(headers): - col = col_start + i - c = ws.cell(row, col, h) - if i == 0: - border = HEADER_BORDER_FIRST - elif i == n-1: - border = HEADER_BORDER_LAST - else: - border = HEADER_BORDER_MID - _apply(c, _font, _fill, border, HEADER_ALIGN) - - -def write_data_rows(ws, data_start, col_start, rows, - center_cols=None, height=None, - font=None, odd_fill=True): - """ - rows: list[list] 각 행의 값. - center_cols: set of 0-based 인덱스 → center align. 나머지 left. - odd_fill: True=홀/짝 교대 배경, False=배경 없음. - """ - n_cols = max((len(r) for r in rows), default=0) - center_cols = center_cols or set() - for i, rowvals in enumerate(rows): - r = data_start + i - if height: - set_row_height(ws, r, height) - is_odd = (i % 2 == 0) - fill = (DATA_FILL_ODD if is_odd else DATA_FILL_EVEN) if odd_fill else None - for j in range(n_cols): - col = col_start + j - c = ws.cell(r, col) - c.value = rowvals[j] if j < len(rowvals) else None - if j == 0: - border = DATA_BORDER_FIRST - elif j == n_cols-1: - border = DATA_BORDER_LAST - else: - border = DATA_BORDER_MID - align = DATA_ALIGN_C if j in center_cols else DATA_ALIGN_L - _apply(c, font or DATA_FONT, fill, border, align) - - -def group_merge(ws, col, data_start, n, key_rows): - """동일 key_rows 값의 연속 행을 col열에서 수직 병합.""" - i = 0 - while i < n: - k = key_rows[i] - if k is None: - i += 1 - continue - j = i + 1 - while j < n and key_rows[j] == k: - j += 1 - if j - i > 1: - L = get_column_letter(col) - ws.merge_cells(f"{L}{data_start+i}:{L}{data_start+j-1}") - i = j diff --git a/.claude/skills/ubisam-deliverables/templates/_task.template.md b/.claude/skills/ubisam-deliverables/templates/_task.template.md deleted file mode 100644 index 35c1a14..0000000 --- a/.claude/skills/ubisam-deliverables/templates/_task.template.md +++ /dev/null @@ -1,32 +0,0 @@ -
-{N}.{단계명} — {프로젝트명} -
-
-{프로젝트코드}-{일련번호} -
- -| 필드 | 값 | -|---|---| -| 유형 | {유형명} | -| 상태 | 해야 할 일 | -| 담당자 / 참조자 | {담당자} / {참조자} | -| 진행률 | **0%** | -| Hashtag | {태그1} / {태그2} | - -## 산출물 정의 -> 세부 × 산출물 × 슬롯 표. 단계별 산출물은 04-stage-deliverables 참조. - -| 세부 | 산출물 | 슬롯 | -|---|---|---| -| {세부} | {산출물} | `{슬롯}/` | - -## 첨부 / 템플릿 -- {파일명 또는 양식 템플릿 위치} - - diff --git a/.claude/skills/ubisam-deliverables/templates/project.yaml.template b/.claude/skills/ubisam-deliverables/templates/project.yaml.template deleted file mode 100644 index 68254f4..0000000 --- a/.claude/skills/ubisam-deliverables/templates/project.yaml.template +++ /dev/null @@ -1,31 +0,0 @@ -# 프로젝트 메타 (템플릿) — {...} 토큰을 실제 값으로 교체 -# 출처: UBISAM 협업관리 › 프로젝트 설정 › 기본정보 / 대상자 - -project_name: "{사업부}_{고객사}_{설비명} 운영SW" -project_kind: "Software" # Software | Hardware -project_code: "{CUST}_{TYPE}_{NN}_{YYYYMMDD}" # 예: CUST_TYPE_01_20260101 -board_type: "Kanban" -status: "업무 진행중" # ubisam-format-map §1 enum 4종만 사용 (임의 변형 금지) - -org: - division: "{사업부}" - team: "{팀}" - -people: - registrant: "{등록자} ({직급})" - pl: "{PL} ({직급})" - -schedule: - contract_date: "{YYYY-MM-DD}" - due_date: "{YYYY-MM-DD}" - -# 권한 3단계: 책임자 → 참여자 → 열람자 -roles: - owners: ["{책임자}"] - participants: ["{참여자1}", "{참여자2}"] - viewers: ["{열람자…}"] - -alarm: - realtime_ticket: true - mail: true - comment: true diff --git a/.claude/skills/ubisam-format-map/SKILL.md b/.claude/skills/ubisam-format-map/SKILL.md deleted file mode 100644 index 61cb4a4..0000000 --- a/.claude/skills/ubisam-format-map/SKILL.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -name: ubisam-format-map -description: Ubisam 협업관리 양식의 공통 enum·스키마·단계↔산출물 슬롯 매핑 레퍼런스. 상태(4종)·일감유형(9종)·진행 6단계(분석/협의·설계·제작·셋업·양산·CS)·일감/프로젝트 필드 스키마·티켓 코드 규칙을 제공. Ubisam 양식으로 산출물을 재생산·재배치·검증하거나, 타사 양식 문서를 Ubisam 단계로 매핑할 때 반드시 이 스킬을 먼저 읽을 것. "Ubisam 양식", "협업관리", "일감 6단계", "산출물 슬롯", "상태/유형 enum" 언급 시 사용. 구분 — 이 스킬은 **조회 전용 사전**이다. 실제로 산출물을 만들거나 고치는 것은 `ubisam-deliverables`(트리 생성)·`ubisam-deliverable-rebuild`(기존 문서 재생산)·`ptop-deliverables`(소스 기준 MD)다. ---- - -# Ubisam 협업관리 양식 맵 (Format Map) - -타사 양식 산출물을 Ubisam 협업관리 양식으로 **재생산·재배치·검증**할 때의 단일 기준 사전이다. -근거 원본(스크린샷 분석)은 아래를 참조하며, 값이 갱신되면 **이 파일과 원본을 함께** 고친다. - -- `docs/[Ubisam산출물]/[분석]/_ubisam-협업관리-용어집(skill-ref).md` — enum 사전(원본) -- `docs/[Ubisam산출물]/[분석]/2026_06_29_협업관리-프로젝트관리-분석.md` — 단계별 산출물 정의 상세 -- `docs/[Ubisam산출물]/ref/` — 화면 캡처 - -> ⚠ 위 3개 경로는 **`ubisam-deliverables` 스캐폴딩 이후에만 존재**하며, `docs/[Ubisam산출물]/`은 -> `.gitignore` 제외 대상이라 clone 직후에는 없다. 없으면 **본문 §1~§5를 유일 기준으로 삼고**, -> 본문이 답하지 못하는 항목은 `미정 — 확인 필요`로 남긴다. 없는 파일을 찾다 멈추지 말 것. - -## 1. 상태(Status) enum — 4종 (전이 순서) - -``` -해야 할 일 → 분석 진행 → 업무 진행중 → 진행 완료 -``` -아래 **ARGB는 xlsx 셀 채우기용**이다. MD·HTML 뱃지 색은 -`ubisam-deliverables/references/02-enums.md`의 HEX 표를 쓴다 (같은 상태, 다른 용도). - -| 상태 | 색(ARGB · xlsx) | 칸반 컬럼 | -|---|---|---| -| 해야 할 일 | `FFD9D9D9` (회색) | Todo | -| 분석 진행 | **미확인** — 원본 스크린샷에서 확인 후 기입 | Select For dev | -| 업무 진행중 | `FF8FAADC` (파랑) | InProgress | -| 진행 완료 | `FFA9D08E` (연두) | Done | - -> `분석 진행`은 이전 판에서 `업무 진행중`과 **같은 ARGB(`FF8FAADC`)로 잘못 적혀 있었다.** -> 같은 색이면 조건부서식이 두 상태를 구분하지 못한다. 실제 값을 확인하기 전까지 지어내지 말고 -> `미확인`으로 두고, 확인되면 이 표를 고친다. 실제 파일 색이 표와 다르면 **파일이 진실원이다.** - -상태 문자열은 위 4개만 사용한다. 임의 변형(예: "완료", "진행중") 금지 — 칸반/조건부서식 매칭이 깨진다. - -> ARGB가 `미확인`인 상태는 **셀 채우기 없이 문자열만 기입**하고 그 사실을 작업 로그에 남긴다. -> 색을 지어내면 조건부서식이 잘못 매칭된다. - -## 2. 일감 유형(Type) enum — 9종 - -오류수정 · 불합리 · 미팅 · 설계 · 개발 · 제작 · 입고셋업 · 적용 및 모니터링 · 요청대응 - -## 3. 진행 6단계 ↔ 기본 일감유형 ↔ 산출물 슬롯 - -| # | 단계 | 기본 유형 | 핵심 산출물(슬롯) | -|---|---|---|---| -| 1 | 분석/협의 | 미팅 | 사양서, CR회의록, 마스터플랜, URS 분석/제어 시나리오 검토 | -| 2 | 설계 | 설계 | HMI 화면정의서·UI 스토리보드·기능명세서 / 시퀀스 다이어그램·인터록 정의서 / 통신맵(Memory·IO·Register)·DB 스키마 / D/R 회의록 | -| 3 | 제작 | 제작 | 개발환경·핵심모듈·UI/메인 시퀀스·시뮬레이션 / 단위·통합 테스트 결과 보고서(Check-List) | -| 4 | 셋업 | 입고셋업 | HW IO/모션 점검 시트 / 파라미터·레시피 백업 / 이슈 로그(Dry Run·Tack Time) / MES 연동 / SAT 결과서 | -| 5 | 양산 | 적용 및 모니터링 | 운영 가이드·매뉴얼(HMI·알람조치) / S/W 최적화 / 최종 버전 동결·마스터 백업 / 프로젝트 완료 보고서 | -| 6 | CS | 요청대응 | 요청대응 이력(가동 후 CS) | - -**타사 양식 → 슬롯 매핑 원칙**: 원본 문서의 목적(요구분석/설계정의/테스트/셋업/운영매뉴얼)을 위 슬롯 키워드와 대조해 단계를 결정한다. 한 문서가 여러 단계에 걸치면 단일 슬롯 배치가 기본값이며 보조 단계를 비고에 병기한다. -**단 분할 여부의 최종 판정은 `ubisam-analyst.md` §4가 소유한다** — 시트/슬라이드 단위로 서로 다른 -슬롯에 배치하는 것이 적절한 문서가 있기 때문이다. 이 절과 충돌하면 analyst §4를 따른다. - -## 4. 일감 필드 스키마 - -| 필드 | 규칙 | -|---|---| -| 제목 | `N.단계명` (예: `2.설계`) | -| 티켓번호 | `{프로젝트코드}-{일련번호}` — 프로젝트코드는 `_meta/project.yaml`에서 읽는다 | -| 유형 | §2 enum 1개 | -| 상태 | §1 enum 1개 | -| 우선순위 | 보통(=Normal) 기본 | -| 담당자/참조자 | `이름(직급)` | -| 진행률 | % | -| 등록일/수정일/종료일 | yyyy/mm/dd (또는 yyyy-mm-dd) | -| 예상시간 | `2w 4d 6h 45m` 형식 | -| Hashtag | 자유 태그 | -| 첨부파일 | 최대 2.93GB | - -## 5. 프로젝트 메타 스키마 - -프로젝트명 · 종류(Software) · 프로젝트형식(Kanban) · 코드명 · 사업부/팀 · PL · 등록자 · 계약일/납기 · 권한(책임자→참여자→열람자). - -**프로젝트 메타의 유일 진실원은 `docs/[Ubisam산출물]/_meta/project.yaml`이다.** -이 스킬에 특정 프로젝트의 값을 적어두지 않는다 — 다른 프로젝트에서 복사해 온 값이 여기 남아 있으면, -그것을 읽은 작성가가 산출물에 그대로 기입하고 검증가는 그 값을 정답으로 대조하게 된다. -즉 **하네스가 잡아야 할 "타설비 잔재"를 하네스 스스로 공급하는 꼴**이 된다. - -`project.yaml`이 없으면 값을 지어내지 말고 `미정 — 확인 필요`로 남기고 사용자에게 묻는다. - -## 6. PTOP 채움 시 참고값 (검증 기준 아님) - -> 아래는 **이 저장소 한정 참고값**이다. §5 원칙대로 프로젝트 메타의 진실원은 `_meta/project.yaml`이며, -> qa는 이 절을 정답으로 대조하지 않는다. `project.yaml`과 어긋나면 `project.yaml`이 우선한다. - - -설비: 각형 배터리 레이저 용접기(ILSOS OC5 PtoP Welder), Aurora 2.0 / .NET 4.8.1 / WPF. -주요 디바이스: PLC(Mitsubishi Melsec·MX Component), Laser Scanner(RTC), Laser(IO Gate), -Digital IO — 구현 클래스는 `PAIX_PTOP`(`EquipmentSetup.cs:153` 등록), 보드 타입은 런타임 -`IOUnitConfig.BoardType` 설정값이다. "Ajin"으로 단정하지 말고 설정을 확인할 것. -메인 시퀀스: `SeqAutoRunPTOP`. PLC 인터페이스: `Machines/ILSOS_PrismaticRD_PTOP/Device/PLC/PLCController.Address.cs`. - -> 재생산 산출물의 **출처(코드 경로/커밋)**를 항상 명시한다 — 검증가가 근거 추적에 사용한다. - -> **규약 바인딩.** 이 스킬은 enum·양식의 **단일 기준**이라 여기서 새는 추측은 하류 전체를 오염시킨다. -> - 확인하지 않은 값·해석은 문장 앞에 `[추론]` 을 붙인다 (`rules.md` #15·#16). 확인 후 표기를 떼고 -> `파일:심볼` 로 바꾼다. 검색은 **`\[추론\]`** 로 이스케이프한다(대괄호=정규식 문자클래스). -> - `미확인`(값을 못 찾음)과 `[추론]`(확인 전 서술)은 축이 다르다 — 대체하지 말고 필요하면 병기한다. -> - 주석·클래스명을 근거로 삼지 않는다 (#1). 위 `BoardType` 이 그 사례다. -> - 모르면 지어내지 말고 모른다고 한다 (#9). diff --git a/.claude/skills/ubisam-ppt-make/SKILL.md b/.claude/skills/ubisam-ppt-make/SKILL.md deleted file mode 100644 index 31a6c05..0000000 --- a/.claude/skills/ubisam-ppt-make/SKILL.md +++ /dev/null @@ -1,162 +0,0 @@ ---- -name: ubisam-ppt-make -description: >- - Ubisam SW 설계서 디자인 시스템으로 .pptx 덱을 만든다. 모든 페이지에 UbiSam 로고, - 고정 폰트(한글=굴림 / 영문=Arial), 파란 accent 컬러. JSON spec을 받아 python-pptx로 렌더링한다. - "Ubisam 설계서 PPT 만들어줘", "유비삼 스타일 덱", "이 양식으로 발표자료", "/ubisam-ppt-make" - 요청 시 사용. `ubisam-deliverables`·`ubisam-deliverable-rebuild`가 PPTX 렌더링을 위임할 때도 - 반드시 이 스킬을 쓴다 — 다른 곳에서 python-pptx로 **덱을 새로 만들지** 않는다. - (예외: `ui_layout_image`가 **기존 pptx에 이미지를 삽입·교체**하는 것은 렌더링이 아니므로 허용.) - 구분 — 기획·조사부터 필요한 일반 발표자료는 `ppt_Agent`, 이 스킬은 **Ubisam 브랜드 spec→pptx 렌더링 전용**. - 맨손 "업데이트"·"다시 실행"만으로는 이 스킬을 고르지 않는다 — 무엇을 만들지 먼저 확인한다. ---- - -# ubisam-ppt-make — Ubisam SW 설계서 deck builder - -Deterministic PPT builder following the design system extracted from -`P-PRJ_BFHB_UBISAM_Ver1.4.pptx` and the user's edited layout showcase -(UbiSam logo placed on every page). Takes a JSON spec and emits a `.pptx` -via python-pptx. - -## When to use - -- The user types `/ubisam-ppt-make` -- Requests like "Ubisam 설계서 PPT 만들어줘" / "유비삼 스타일 덱" / "this format으로" -- New design-document presentations that must keep Ubisam branding -- **`ubisam-deliverables` 스킬이 PPTX 생성을 위임할 때** — deliverables는 spec JSON만 준비하고 렌더링은 반드시 이 스킬의 `build_deck.py`로 위임한다 - -> **역할 경계**: `ubisam-ppt-make`는 PPTX 렌더링 엔진. JSON spec → `.pptx` 변환만 담당. -> 산출물 구조·MD·xlsx 관리는 `ubisam-deliverables` 스킬이 담당. - -## Design system (fixed) - -- Slide: 16:9 (13.333 × 7.5 in) -- **슬라이드 마스터 배경** (모든 pptx 자동 적용): - - 캔버스: **`WHITE`** — `_apply_master_background()`가 마스터와 전 레이아웃에 흰색을 적용한다 - (`build_deck.py:55-73`). `BG_SOFT`(#F4F7FA)는 **패널·표 짝수행 fill 전용**이지 배경색이 아니다 - - 하단 accent 바: `#4A8DCB` h=0.15in @ y=7.35in (마스터 공통) - - cover·divider·closing은 자체 full rect로 덮음 - - 캔버스 배경은 `_apply_master_background()`가 `WHITE`로 고정한다. spec JSON으로 재정의할 수 없다 -- Accent: `#4A8DCB` (blue), dark `#2F5E8C`; warn `#E53E3E` -- Ink `#262A2E`, sub-gray `#6B7278`, soft panel `#F4F7FA` -- **Font rule (do not change): 한글=굴림, 영문=Arial** — applied to every run -- **UbiSam logo on every page**: cover = bottom-right, all others = top-right -- Header pattern: `0X.` badge + title + KO subtitle + split accent bar -- Footer: `Ubisam | ` + page number (content pages only) - -## 12 layout types (`slide.type`) - -Document layouts: - -| type | purpose | key fields | -|------|---------|-----------| -| `cover` | 표지 | `tag, title, subtitles[], team, contacts[]` | -| `history` | 변경 이력 표 | `rows[] = [No,Version,날짜,변경자,내용]` | -| `agenda` | 목차 그리드(≤6) | `items[] = {no,title,sub}` | -| `divider` | 섹션 간지(큰 숫자) | `no, title, subtitle` | -| `content` | 4분할 패널 | `no, title, subtitle, panels[] = {title,body}` | -| `flow` | 시퀀스 플로우차트 | `no, title, subtitle, steps[]={title,code,kind}, branch{title,sub}` | -| `table` | 스펙/IO 표 | `no, title, headers[], widths[], center_cols[], rows[][]` | -| `closing` | 마무리 | `title, message, team, contacts[]` | - -Manual layouts (HMI Manual / 27번): - -| type | purpose | key fields | -|------|---------|-----------| -| `screen_guide` | 화면 설명(캡처+번호 콜아웃) | `no, title, caption, image(PNG경로), items[]={title,desc,pos:[x,y]}` | -| `procedure` | 조작 절차(번호 단계) | `no, title, steps[]={title,desc}` | -| `icon_ref` | 버튼/아이콘 설명(3열 카드, ≤6) | `no, title, items[]={icon,name,func}` | -| `alarm` | 알람·조치(주의 배너+표) | `no, title, notice, rows[]=[코드,알람명,원인,조치]` | - -`kind` for flow steps: `"proc"` (process box) or `"dec"` (decision, blue outline). -`pos` in `screen_guide` items = callout marker offset (inch) inside the capture box. -Page numbers auto-increment over content/manual pages; cover/divider/closing excluded. -`divider`/`closing` use a white background with a `#0070C0` / `#2F5E8C` block. - -## Choosing a layout for each piece of data - -Match every chunk of source/analysis data to the layout whose intent fits it — -do not force everything into `table`. Full rules + disambiguation in -[`reference/layout_selection.md`](reference/layout_selection.md). Cheat sheet: - -- ordered **human** steps → `procedure` · machine sequence **with branches** → `flow` -- 2–4 facets, one line each → `content` · repeating rows/cols → `table` -- annotate ONE screenshot → `screen_guide` · button/icon legend → `icon_ref` -- fault → cause → action (+safety) → `alarm` · revision log → `history` - -## Workflow - -1. **Gather info** — topic, doc title, sections, slide contents, contacts. - 내용이 없으면 **무엇을 만들지 되묻는다.** 샘플 showcase는 사용자가 **명시적으로 샘플/레이아웃 - 예시를 요청했을 때만** 만든다 — 그냥 만들면 원하지 않은 13장 덱이 나온다. -2. **Classify each data chunk → layout** using the guide above, then - **write the spec JSON** — see `examples/showcase.json` and the type tables. - Reuse the original BFHB sample text only when the user wants the showcase. -3. **Run the builder**: - 저장소 루트에서 한 줄로 실행한다 (`cd` 하지 않는다 — 출력이 스킬 폴더로 새는 것을 막기 위함): - ```bash - PYTHONUTF8=1 py .claude/skills/ubisam-ppt-make/build_deck.py --input --output <출력 .pptx 절대·상대 경로> - ``` - `PYTHONUTF8=1`은 반드시 **같은 줄** 접두로 둔다. 별도 줄에 두면 적용되지 않아 한글이 깨진다. -4. **Verify** — render to PNG and eyeball every slide (see Verification). -5. **Report** — output path + slide summary. - -## Spec schema (minimal) - -```json -{ - "doc_title": "{문서 제목}", - "slides": [ - { "type": "cover", "title": "...", "subtitles": ["..."], - "team": "{조직명}", "contacts": ["{이름} {직급} {email}"] }, - { "type": "divider", "no": "01", "title": "...", "subtitle": "..." }, - { "type": "content", "no": "02.", "title": "...", "subtitle": "...", - "panels": [ {"title": "...", "body": "..."} ] } - ] -} -``` - -A full working spec is in [`examples/showcase.json`](examples/showcase.json). - -## Verification - -**가용성을 먼저 확인한다.** PNG 렌더 검증은 PowerPoint COM이 있어야 한다 — -`powershell -c "New-Object -ComObject PowerPoint.Application"` 이 실패하면 렌더 검증을 생략하고 -보고에 **`PNG 검증 미수행 — PowerPoint 부재`** 로 명시한다(검증했다고 하지 않는다). -이 경우 아래 **폰트 감사**만 수행한다 — 그건 zipfile만으로 되므로 항상 가능하다. - -PowerPoint가 있으면: Export every slide to PNG and inspect; check no overflow/overlap, logo on -every page, and 한글=굴림 / 영문=Arial on all runs. - -```powershell -# PowerPoint COM export (Windows, PowerPoint installed) -$ppt = New-Object -ComObject PowerPoint.Application -$pres = $ppt.Presentations.Open($pptx, $true, $false, $false) -$i=1; foreach ($s in $pres.Slides) { $s.Export("$dir/slide$i.png","PNG",1280,720); $i++ } -$pres.Close(); $ppt.Quit() -``` - -Font audit (every `rPr` must show `ea=굴림`, `latin=Arial`): -```bash -PYTHONUTF8=1 py -c "import zipfile,re,sys;from collections import Counter;z=zipfile.ZipFile(sys.argv[1]);\ -[print(Counter(re.findall(r'`/`` so Korean renders in 굴림. Always go through it. -- Logo asset: `assets/Ubisam_logo_transparent.png`. On dark divider/closing the - colored logo has lower contrast but matches the user's original placement. -- Keep `.md` files under 200 lines (`rules.md` #4); split if it grows. -- **생성·덮어쓸 `.pptx` 경로를 먼저 제시하고 승인받는다** (`rules.md` #2). 같은 이름이 이미 있으면 - 덮어쓰기 전에 무엇이 사라지는지 한 줄로 알린다 — 렌더링은 되돌릴 수 없다. -- ⚠ **`build_deck.py` 의 `__main__` 데모와 `examples/showcase.json` 은 타 프로젝트(P-PRJ BFHB) 실데이터다.** - 조직명·담당자·이력 행을 **그대로 복사하지 않는다.** 값은 `_meta/project.yaml` 또는 사용자 입력에서 온다. -- **`table` 높이 상한**: 표는 `_TABLE_MAX_H = 5.3"` (y 1.7" ~ 7.0")로 자동 제한. - 행이 많아도 푸터(`Ubisam | `, y=7.05")를 절대 침범하지 않는다. - 행 높이는 `min(0.5×rows, 5.3) / rows`로 균등 압축된다. - -> 보고는 `rules.md` #11~13 출력 형식을 따르고(수정 줄=초록 화살표, 단어=주황, 미변경=기본색), -> 단계 전환마다 진행을 한 줄로 알리며(#10), 끝에 관련 `.md` 갱신 필요 여부를 묻는다(#6). diff --git a/.claude/skills/ubisam-ppt-make/assets/Ubisam_logo.gif b/.claude/skills/ubisam-ppt-make/assets/Ubisam_logo.gif deleted file mode 100644 index 3c22428..0000000 Binary files a/.claude/skills/ubisam-ppt-make/assets/Ubisam_logo.gif and /dev/null differ diff --git a/.claude/skills/ubisam-ppt-make/assets/Ubisam_logo_transparent.png b/.claude/skills/ubisam-ppt-make/assets/Ubisam_logo_transparent.png deleted file mode 100644 index 42d4217..0000000 Binary files a/.claude/skills/ubisam-ppt-make/assets/Ubisam_logo_transparent.png and /dev/null differ diff --git a/.claude/skills/ubisam-ppt-make/build_deck.py b/.claude/skills/ubisam-ppt-make/build_deck.py deleted file mode 100644 index ed4d91a..0000000 --- a/.claude/skills/ubisam-ppt-make/build_deck.py +++ /dev/null @@ -1,752 +0,0 @@ -# -*- coding: utf-8 -*- -""" -ubisam-ppt-make — Ubisam SW 설계서 deck builder. - -Design system extracted from P-PRJ_BFHB_UBISAM_Ver1.4.pptx and the user's -edited layout_showcase (UbiSam logo on every page). - -Font rule (fixed): 한글=굴림, 영문=Arial. - -Usage: - python build_deck.py # build sample showcase - python build_deck.py --input spec.json --output deck.pptx -""" -import os -import json -import argparse -from pptx import Presentation -from pptx.util import Inches, Pt -from pptx.dml.color import RGBColor -from pptx.enum.text import PP_ALIGN, MSO_ANCHOR -from pptx.enum.shapes import MSO_SHAPE -from pptx.oxml.ns import qn -from pptx.parts.image import ImagePart -from pptx.opc.constants import RELATIONSHIP_TYPE as RT -from pptx.opc.packuri import PackURI -from lxml import etree - -HERE = os.path.dirname(os.path.abspath(__file__)) -LOGO = os.path.join(HERE, "assets", "Ubisam_logo_transparent.png") - -# ---- design tokens ---- -ACCENT = RGBColor(0x4A, 0x8D, 0xCB) -ACCENT_D = RGBColor(0x2F, 0x5E, 0x8C) -INK = RGBColor(0x26, 0x2A, 0x2E) -SUB = RGBColor(0x6B, 0x72, 0x78) -LINE = RGBColor(0xD9, 0xDD, 0xE1) -BG_SOFT = RGBColor(0xF4, 0xF7, 0xFA) -WHITE = RGBColor(0xFF, 0xFF, 0xFF) -WARN = RGBColor(0xE5, 0x3E, 0x3E) -PALE = RGBColor(0xDD, 0xEA, 0xF6) -BLUE2 = RGBColor(0x00, 0x70, 0xC0) # divider/closing block blue - -KFONT = "굴림" -EFONT = "Arial" - -EMU_W = Inches(13.333) -EMU_H = Inches(7.5) - -_NS_P = "http://schemas.openxmlformats.org/presentationml/2006/main" -_NS_A = "http://schemas.openxmlformats.org/drawingml/2006/main" -_NS_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships" - - -# ---------- master background ---------- -def _apply_master_background(prs): - """슬라이드 마스터에 흰 배경 + Ubisam 로고 워터마크 + 하단 accent 바 적용. - 모든 슬라이드가 상속. cover·divider·closing은 자체 rect로 덮음.""" - master = prs.slide_master - spTree = master.shapes._spTree - - # 1. 배경: WHITE - try: - master.background.fill.solid() - master.background.fill.fore_color.rgb = WHITE - except Exception: - pass - for layout in prs.slide_layouts: - try: - layout.background.fill.solid() - layout.background.fill.fore_color.rgb = WHITE - except Exception: - pass - - # 2. Ubisam 로고 워터마크 (하단 전체 폭, 15% 투명도) - if os.path.exists(LOGO): - try: - with open(LOGO, "rb") as f: - blob = f.read() - pkg = master.part._package - img_part = ImagePart( - PackURI("/ppt/media/ubisam_master_wm.png"), "image/png", pkg, blob - ) - rId = master.part.relate_to(img_part, RT.IMAGE) - W, H = int(EMU_W), int(Inches(2.5)) - T = int(EMU_H) - H - wm_xml = ( - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - ) - spTree.append(etree.fromstring(wm_xml.encode("utf-8"))) - except Exception: - pass - - # 3. 하단 accent 바 - hex_c = f"{ACCENT[0]:02X}{ACCENT[1]:02X}{ACCENT[2]:02X}" - bar_xml = ( - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - f'' - ) - try: - spTree.append(etree.fromstring(bar_xml.encode("utf-8"))) - except Exception: - pass - - -# ---------- text / shape helpers ---------- -def _set_font(run, size=None, bold=None, color=None, italic=None): - f = run.font - if size is not None: - f.size = Pt(size) - if bold is not None: - f.bold = bold - if italic is not None: - f.italic = italic - if color is not None: - f.color.rgb = color - f.name = EFONT - rPr = run._r.get_or_add_rPr() - for tag in ("a:ea", "a:cs"): - el = rPr.find(qn(tag)) - if el is None: - el = rPr.makeelement(qn(tag), {}) - rPr.append(el) - el.set("typeface", KFONT if tag == "a:ea" else EFONT) - - -def add_text(slide, l, t, w, h, lines, align=PP_ALIGN.LEFT, anchor=MSO_ANCHOR.TOP): - tb = slide.shapes.add_textbox(l, t, w, h) - tf = tb.text_frame - tf.word_wrap = True - tf.vertical_anchor = anchor - for m in ("margin_left", "margin_right", "margin_top", "margin_bottom"): - setattr(tf, m, 0) - for i, spec in enumerate(lines): - text, size, bold, color = spec[0], spec[1], spec[2], spec[3] - a = spec[4] if len(spec) > 4 else align - p = tf.paragraphs[0] if i == 0 else tf.add_paragraph() - p.alignment = a - r = p.add_run() - r.text = text - _set_font(r, size=size, bold=bold, color=color) - return tb - - -def rect(slide, l, t, w, h, fill=None, line_color=None, line_w=None, - shape=MSO_SHAPE.RECTANGLE): - sp = slide.shapes.add_shape(shape, l, t, w, h) - sp.shadow.inherit = False - if fill is None: - sp.fill.background() - else: - sp.fill.solid() - sp.fill.fore_color.rgb = fill - if line_color is None: - sp.line.fill.background() - else: - sp.line.color.rgb = line_color - sp.line.width = Pt(line_w or 0.75) - if sp.has_text_frame: - sp.text_frame.word_wrap = True - return sp - - -def blank_slide(prs): - return prs.slides.add_slide(prs.slide_layouts[6]) - - -def add_logo(slide, where="top", left=None, top=None, height=None): - """UbiSam logo on every page. cover=bottom-right, others=top-right. - left/top/height override the top-right default (in inches).""" - if not os.path.exists(LOGO): - return - if where == "bottom": - slide.shapes.add_picture(LOGO, Inches(10.55), Inches(6.35), height=Inches(0.62)) - else: - slide.shapes.add_picture(LOGO, Inches(10.55 if left is None else left), - Inches(0.5 if top is None else top), - height=Inches(0.55 if height is None else height)) - - -def header(slide, no, title_en, title_ko=None): - if no: - rect(slide, Inches(0.55), Inches(0.42), Inches(0.62), Inches(0.46), fill=ACCENT) - add_text(slide, Inches(0.55), Inches(0.42), Inches(0.62), Inches(0.46), - [(no, 16, True, WHITE, PP_ALIGN.CENTER)], anchor=MSO_ANCHOR.MIDDLE) - tx = 1.32 if no else 0.55 - add_text(slide, Inches(tx), Inches(0.40), Inches(8.6), Inches(0.5), - [(title_en, 22, True, INK)], anchor=MSO_ANCHOR.MIDDLE) - if title_ko: - add_text(slide, Inches(tx + 0.02), Inches(0.86), Inches(8.6), Inches(0.32), - [(title_ko, 12, False, SUB)]) - rect(slide, Inches(0.55), Inches(1.22), Inches(11.4), Inches(0.035), fill=ACCENT) - rect(slide, Inches(0.55), Inches(1.22), Inches(2.2), Inches(0.035), fill=ACCENT_D) - - -def footer(slide, page, doc_title): - add_text(slide, Inches(0.55), Inches(7.05), Inches(7.0), Inches(0.3), - [("Ubisam | " + doc_title, 9, False, SUB)]) - if page is not None: - add_text(slide, Inches(11.0), Inches(7.05), Inches(1.78), Inches(0.3), - [(str(page), 9, False, SUB, PP_ALIGN.RIGHT)]) - - -def num_badge(slide, l, t, dia, n, fill=ACCENT, color=WHITE, size=14): - rect(slide, Inches(l), Inches(t), Inches(dia), Inches(dia), fill=fill, shape=MSO_SHAPE.OVAL) - add_text(slide, Inches(l), Inches(t), Inches(dia), Inches(dia), - [(str(n), size, True, color, PP_ALIGN.CENTER)], anchor=MSO_ANCHOR.MIDDLE) - - -# ---------- layouts ---------- -def L_cover(prs, d): - s = blank_slide(prs) - rect(s, 0, 0, EMU_W, EMU_H, fill=WHITE) - rect(s, 0, 0, Inches(0.28), EMU_H, fill=ACCENT) - rect(s, Inches(0.28), 0, Inches(0.06), EMU_H, fill=ACCENT_D) - rect(s, Inches(0.9), Inches(1.7), Inches(2.4), Inches(0.42), fill=BG_SOFT) - add_text(s, Inches(0.9), Inches(1.7), Inches(2.4), Inches(0.42), - [(d.get("tag", "SW DESIGN DOCUMENT"), 11, True, ACCENT, PP_ALIGN.CENTER)], - anchor=MSO_ANCHOR.MIDDLE) - add_text(s, Inches(0.9), Inches(2.35), Inches(10.0), Inches(1.2), - [(d["title"], 40, True, INK)]) - subs = d.get("subtitles", []) - add_text(s, Inches(0.92), Inches(3.55), Inches(10.5), Inches(0.9), - [(t, 15 if i == 0 else 12, False, SUB) for i, t in enumerate(subs)]) - rect(s, Inches(0.92), Inches(4.7), Inches(3.2), Inches(0.03), fill=LINE) - contacts = d.get("contacts", []) - cl = [(d.get("team", "미정 — 확인 필요"), 13, True, INK)] - cl += [(c, 11, False, SUB) for c in contacts] - add_text(s, Inches(0.92), Inches(4.95), Inches(8.0), Inches(1.4), cl) - add_logo(s, "bottom") - return s - - -def L_history(prs, d): - s = blank_slide(prs) - header(s, d.get("no", "00."), d.get("title", "변경 이력"), d.get("subtitle", "Revision History")) - cols = [("No.", 0.55, 0.55), ("Version", 1.4, 1.1), ("변경일자", 2.5, 1.5), - ("변경자", 4.0, 1.3), ("변경 내용", 5.3, 6.65)] - rows = d.get("rows", []) - top, rh = 1.7, 0.5 - rect(s, Inches(0.55), Inches(top), Inches(11.4), Inches(rh), fill=ACCENT) - for label, x, w in cols: - add_text(s, Inches(x), Inches(top), Inches(w), Inches(rh), - [(label, 12, True, WHITE, PP_ALIGN.CENTER)], anchor=MSO_ANCHOR.MIDDLE) - for i, row in enumerate(rows): - y = top + rh + i * rh - if i % 2 == 1: - rect(s, Inches(0.55), Inches(y), Inches(11.4), Inches(rh), fill=BG_SOFT) - for (label, x, w), val in zip(cols, row): - al = PP_ALIGN.LEFT if label == "변경 내용" else PP_ALIGN.CENTER - xx = x + 0.1 if label == "변경 내용" else x - add_text(s, Inches(xx), Inches(y), Inches(w), Inches(rh), - [(str(val), 11, False, INK, al)], anchor=MSO_ANCHOR.MIDDLE) - rect(s, Inches(0.55), Inches(y + rh), Inches(11.4), Inches(0.012), fill=LINE) - add_logo(s) - footer(s, d.get("page"), d.get("doc_title", "")) - return s - - -def L_agenda(prs, d): - s = blank_slide(prs) - header(s, "", d.get("title", "Contents"), d.get("subtitle", "목차")) - items = d.get("items", []) - cw, ch = 5.55, 1.45 - gx, gy = 0.55, 1.75 - for i, it in enumerate(items[:6]): - r, c = divmod(i, 2) - x = gx + c * (cw + 0.3) - y = gy + r * (ch + 0.25) - rect(s, Inches(x), Inches(y), Inches(cw), Inches(ch), fill=BG_SOFT) - rect(s, Inches(x), Inches(y), Inches(0.08), Inches(ch), fill=ACCENT) - add_text(s, Inches(x + 0.25), Inches(y + 0.18), Inches(1.2), Inches(1.0), - [(it.get("no", ""), 34, True, ACCENT)], anchor=MSO_ANCHOR.MIDDLE) - add_text(s, Inches(x + 1.55), Inches(y + 0.3), Inches(cw - 1.7), Inches(0.9), - [(it.get("title", ""), 17, True, INK), (it.get("sub", ""), 11, False, SUB)], - anchor=MSO_ANCHOR.MIDDLE) - add_logo(s) - footer(s, d.get("page"), d.get("doc_title", "")) - return s - - -def L_divider(prs, d): - s = blank_slide(prs) - rect(s, 0, 0, EMU_W, EMU_H, fill=WHITE) - rect(s, 0, Inches(3.88), EMU_W, Inches(3.62), fill=BLUE2) - add_text(s, Inches(0.9), Inches(1.3), Inches(6.0), Inches(2.2), - [(d.get("no", "01"), 130, True, BLUE2)], anchor=MSO_ANCHOR.MIDDLE) - rect(s, Inches(0.95), Inches(4.05), Inches(2.4), Inches(0.06), fill=WHITE) - add_text(s, Inches(0.95), Inches(4.25), Inches(10.0), Inches(0.84), - [(d.get("title", ""), 30, True, WHITE), (d.get("subtitle", ""), 20, False, PALE)]) - add_logo(s, left=11.3, top=0.55, height=0.5) - return s - - -def L_content(prs, d): - s = blank_slide(prs) - header(s, d.get("no", "02."), d.get("title", ""), d.get("subtitle")) - panels = d.get("panels", []) - pw, ph = 5.55, 2.35 - gx, gy = 0.55, 1.65 - for i, p in enumerate(panels[:4]): - r, c = divmod(i, 2) - x = gx + c * (pw + 0.3) - y = gy + r * (ph + 0.25) - rect(s, Inches(x), Inches(y), Inches(pw), Inches(ph), fill=WHITE, line_color=LINE, line_w=1.0) - rect(s, Inches(x), Inches(y), Inches(pw), Inches(0.42), fill=BG_SOFT) - add_text(s, Inches(x + 0.2), Inches(y), Inches(pw - 0.4), Inches(0.42), - [(p.get("title", ""), 13, True, ACCENT_D)], anchor=MSO_ANCHOR.MIDDLE) - add_text(s, Inches(x + 0.2), Inches(y + 0.42), Inches(pw - 0.4), Inches(ph - 0.42), - [("〔 " + p.get("body", "") + " 〕", 11, False, SUB, PP_ALIGN.CENTER)], - anchor=MSO_ANCHOR.MIDDLE) - add_logo(s) - footer(s, d.get("page"), d.get("doc_title", "")) - return s - - -def L_flow(prs, d): - s = blank_slide(prs) - header(s, d.get("no", "03."), d.get("title", "Sequence Flowchart"), d.get("subtitle")) - steps = d.get("steps", []) - branch = d.get("branch") - cx, bw = 4.55, 3.0 - y, gap = 1.6, 0.46 - prev_bottom, dec_y = None, None - for title, code, kind in [(s2.get("title", ""), s2.get("code", ""), s2.get("kind", "proc")) for s2 in steps]: - h = 0.58 if kind == "dec" else 0.52 - if kind == "dec" and dec_y is None: - dec_y = y - lc = ACCENT if kind == "dec" else SUB - rect(s, Inches(cx), Inches(y), Inches(bw), Inches(h), fill=WHITE, - line_color=lc, line_w=1.5 if kind == "dec" else 1.0, - shape=MSO_SHAPE.ROUNDED_RECTANGLE) - add_text(s, Inches(cx), Inches(y + 0.04), Inches(bw), Inches(h - 0.04), - [(title, 12, True, INK, PP_ALIGN.CENTER), (code, 9, False, ACCENT_D, PP_ALIGN.CENTER)], - anchor=MSO_ANCHOR.MIDDLE) - if prev_bottom is not None: - ln = s.shapes.add_connector(2, Inches(cx + bw / 2), Inches(prev_bottom), - Inches(cx + bw / 2), Inches(y)) - ln.line.color.rgb = ACCENT - ln.line.width = Pt(1.5) - prev_bottom = y + h - y += h + gap - if branch and dec_y is not None: - bh = 0.58 - by = dec_y - rect(s, Inches(1.7), Inches(by), Inches(1.9), Inches(bh), fill=BG_SOFT, - line_color=SUB, line_w=1.0, shape=MSO_SHAPE.ROUNDED_RECTANGLE) - add_text(s, Inches(1.7), Inches(by), Inches(1.9), Inches(bh), - [(branch.get("title", ""), 11, True, WARN, PP_ALIGN.CENTER), - (branch.get("sub", ""), 9, False, SUB, PP_ALIGN.CENTER)], anchor=MSO_ANCHOR.MIDDLE) - ln = s.shapes.add_connector(2, Inches(cx), Inches(by + bh / 2), Inches(3.6), Inches(by + bh / 2)) - ln.line.color.rgb = WARN - ln.line.width = Pt(1.25) - add_logo(s) - footer(s, d.get("page"), d.get("doc_title", "")) - return s - - -def _fill_cell(cell, text, size, bold, color, center=False): - cell.vertical_anchor = MSO_ANCHOR.MIDDLE - cell.margin_left = Inches(0.08) - cell.margin_right = Inches(0.08) - cell.margin_top = Inches(0.02) - cell.margin_bottom = Inches(0.02) - tf = cell.text_frame - tf.word_wrap = True - p = tf.paragraphs[0] - p.alignment = PP_ALIGN.CENTER if center else PP_ALIGN.LEFT - r = p.add_run() - r.text = str(text) - _set_font(r, size=size, bold=bold, color=color) - - -_TABLE_TOP = 1.7 # table body starts here (inches) -_TABLE_MAX_H = 5.3 # max table height: footer y(7.05) - table top(1.7) - margin(0.05) - -def L_table(prs, d): - s = blank_slide(prs) - header(s, d.get("no", "06."), d.get("title", ""), d.get("subtitle")) - headers = d.get("headers", []) - widths = d.get("widths") or [11.4 / len(headers)] * len(headers) - data = d.get("rows", []) - center_cols = set(d.get("center_cols", [])) - rows = len(data) + 1 - tbl_h = min(0.5 * rows, _TABLE_MAX_H) - tbl = s.shapes.add_table(rows, len(headers), Inches(0.55), Inches(_TABLE_TOP), - Inches(11.4), Inches(tbl_h)).table - for c, w in enumerate(widths): - tbl.columns[c].width = Inches(w) - for c, hd in enumerate(headers): - cell = tbl.cell(0, c) - cell.fill.solid() - cell.fill.fore_color.rgb = ACCENT - _fill_cell(cell, hd, 12, True, WHITE, center=True) - for r, row in enumerate(data, start=1): - for c, val in enumerate(row): - cell = tbl.cell(r, c) - cell.fill.solid() - cell.fill.fore_color.rgb = BG_SOFT if r % 2 == 0 else WHITE - _fill_cell(cell, val, 11, False, INK, center=(c in center_cols)) - add_logo(s) - footer(s, d.get("page"), d.get("doc_title", "")) - return s - - -def L_closing(prs, d): - s = blank_slide(prs) - rect(s, 0, 0, EMU_W, EMU_H, fill=WHITE) - rect(s, 0, Inches(5.0), EMU_W, Inches(2.5), fill=ACCENT_D) - add_text(s, Inches(0.83), Inches(1.8), Inches(11.0), Inches(1.62), - [(d.get("title", "Thank You"), 96, True, BLUE2)]) - if d.get("message"): - add_text(s, Inches(0.95), Inches(3.5), Inches(11.0), Inches(0.5), - [(d["message"], 14, False, INK)]) - cl = [(d.get("team", "미정 — 확인 필요"), 14, True, WHITE)] - cl += [(c, 12, False, PALE) for c in d.get("contacts", [])] - add_text(s, Inches(0.95), Inches(5.35), Inches(11.0), Inches(1.4), cl) - add_logo(s, left=10.55, top=0.55, height=0.6) - return s - - -# ---------- manual layouts ---------- -REGION = RGBColor(0xFF, 0x00, 0x00) # red region-highlight border (matches manual edit) - - -def _img_px_size(path): - try: - from PIL import Image - with Image.open(path) as im: - return im.size - except Exception: - return None - - -def _fit_image(slide, path, bx, by, bw, bh): - """Add picture fitted (aspect-preserved, centered) inside box (inches). - Returns the placed rect (left, top, w, h) in inches.""" - pic = slide.shapes.add_picture(path, Inches(bx), Inches(by), width=Inches(bw)) - if pic.height > Inches(bh): - sp = pic._element - sp.getparent().remove(sp) - pic = slide.shapes.add_picture(path, Inches(bx), Inches(by), height=Inches(bh)) - pic.left = Inches(bx) + (Inches(bw) - pic.width) // 2 - pic.top = Inches(by) + (Inches(bh) - pic.height) // 2 - return (pic.left / 914400.0, pic.top / 914400.0, - pic.width / 914400.0, pic.height / 914400.0) - - -def _norm_boxes(it): - """Return list of [x,y,w,h] pixel boxes from item's box/boxes field.""" - b = it.get("boxes") or it.get("box") - if not b: - return [] - return b if isinstance(b[0], (list, tuple)) else [b] - - -def L_screen_guide(prs, d): - """화면 설명: 캡처 영역(좌) + 번호 콜아웃(우). 이미지 위 영역 박스+번호 마커 지원.""" - s = blank_slide(prs) - header(s, d.get("no", "07."), d.get("title", "화면 설명"), d.get("subtitle")) - sx, sy, sw, sh_ = 0.55, 1.7, 7.3, 5.0 - rect(s, Inches(sx), Inches(sy), Inches(sw), Inches(sh_), fill=BG_SOFT, line_color=LINE, line_w=1.0) - items = d.get("items", []) - img = d.get("image") - if img and os.path.exists(img): - il, it_, iw, ih = _fit_image(s, img, sx + 0.05, sy + 0.05, sw - 0.1, sh_ - 0.1) - px = _img_px_size(img) - if px: - scale = iw / px[0] # inches per pixel (aspect preserved) - mdia = 0.30 - for i, item in enumerate(items): - for j, bx in enumerate(_norm_boxes(item)): - rl, rt = il + bx[0] * scale, it_ + bx[1] * scale - rw, rh = bx[2] * scale, bx[3] * scale - rect(s, Inches(rl), Inches(rt), Inches(rw), Inches(rh), - fill=None, line_color=REGION, line_w=1.5) - if j == 0: # number marker at first box's top-left corner - num_badge(s, rl, rt, mdia, i + 1, size=12) - else: - add_text(s, Inches(sx), Inches(sy), Inches(sw), Inches(sh_), - [("〔 " + d.get("caption", "화면 캡처 영역") + " 〕", 12, False, SUB, PP_ALIGN.CENTER)], - anchor=MSO_ANCHOR.MIDDLE) - rx, rw = 8.15, 4.65 - n = max(len(items), 1) - rh = min(1.0, (sh_ + 0.0) / n) - for i, it in enumerate(items): - pos = it.get("pos") - if pos: - num_badge(s, sx + pos[0], sy + pos[1], 0.34, i + 1, size=12) - ly = sy + i * rh - num_badge(s, rx, ly + 0.03, 0.34, i + 1, size=12) - add_text(s, Inches(rx + 0.5), Inches(ly - 0.02), Inches(rw - 0.5), Inches(rh), - [(it.get("title", ""), 13, True, INK), (it.get("desc", ""), 11, False, SUB)]) - add_logo(s) - footer(s, d.get("page"), d.get("doc_title", "")) - return s - - -def L_procedure(prs, d): - """조작 절차: 세로 번호 단계.""" - s = blank_slide(prs) - header(s, d.get("no", "07."), d.get("title", "조작 절차"), d.get("subtitle")) - steps = d.get("steps", []) - y0, y1 = 1.75, 6.8 - n = max(len(steps), 1) - rh = min(1.1, (y1 - y0) / n) - for i, st in enumerate(steps): - y = y0 + i * rh - if i % 2 == 1: - rect(s, Inches(0.55), Inches(y), Inches(11.4), Inches(rh - 0.12), fill=BG_SOFT) - num_badge(s, 0.75, y + (rh - 0.12 - 0.5) / 2, 0.5, i + 1, size=18) - add_text(s, Inches(1.55), Inches(y), Inches(10.3), Inches(rh - 0.12), - [(st.get("title", ""), 15, True, INK), (st.get("desc", ""), 12, False, SUB)], - anchor=MSO_ANCHOR.MIDDLE) - add_logo(s) - footer(s, d.get("page"), d.get("doc_title", "")) - return s - - -def L_icon_ref(prs, d): - """버튼/아이콘 설명: 카드 그리드(3열).""" - s = blank_slide(prs) - header(s, d.get("no", "07."), d.get("title", "버튼 설명"), d.get("subtitle")) - items = d.get("items", []) - cw, ch, gx, gy, gp = 3.6, 2.35, 0.55, 1.75, 0.3 - for i, it in enumerate(items[:6]): - r, c = divmod(i, 3) - x = gx + c * (cw + gp) - y = gy + r * (ch + 0.3) - rect(s, Inches(x), Inches(y), Inches(cw), Inches(ch), fill=WHITE, line_color=LINE, line_w=1.0) - rect(s, Inches(x + (cw - 1.1) / 2), Inches(y + 0.3), Inches(1.1), Inches(1.1), - fill=BG_SOFT, line_color=ACCENT, line_w=1.0, shape=MSO_SHAPE.ROUNDED_RECTANGLE) - add_text(s, Inches(x + (cw - 1.1) / 2), Inches(y + 0.3), Inches(1.1), Inches(1.1), - [(it.get("icon", "ICON"), 11, True, ACCENT, PP_ALIGN.CENTER)], anchor=MSO_ANCHOR.MIDDLE) - add_text(s, Inches(x + 0.15), Inches(y + 1.5), Inches(cw - 0.3), Inches(0.35), - [(it.get("name", ""), 13, True, INK, PP_ALIGN.CENTER)]) - add_text(s, Inches(x + 0.15), Inches(y + 1.85), Inches(cw - 0.3), Inches(0.45), - [(it.get("func", ""), 10, False, SUB, PP_ALIGN.CENTER)]) - add_logo(s) - footer(s, d.get("page"), d.get("doc_title", "")) - return s - - -def L_alarm(prs, d): - """알람·조치: 주의 배너 + 표.""" - s = blank_slide(prs) - header(s, d.get("no", "07."), d.get("title", "알람 및 조치 방법"), d.get("subtitle")) - rect(s, Inches(0.55), Inches(1.65), Inches(11.4), Inches(0.55), - fill=RGBColor(0xFF, 0xF4, 0xD6), line_color=RGBColor(0xF0, 0xB4, 0x29), line_w=1.0) - rect(s, Inches(0.7), Inches(1.78), Inches(0.95), Inches(0.3), fill=WARN, shape=MSO_SHAPE.ROUNDED_RECTANGLE) - add_text(s, Inches(0.7), Inches(1.78), Inches(0.95), Inches(0.3), - [("주의", 11, True, WHITE, PP_ALIGN.CENTER)], anchor=MSO_ANCHOR.MIDDLE) - add_text(s, Inches(1.8), Inches(1.65), Inches(10.0), Inches(0.55), - [(d.get("notice", "알람 발생 시 아래 조치 방법을 순서대로 수행하십시오."), 12, True, INK)], - anchor=MSO_ANCHOR.MIDDLE) - headers = d.get("headers", ["코드", "알람명", "발생 원인", "조치 방법"]) - widths = d.get("widths") or [1.4, 3.0, 3.5, 3.5] - data = d.get("rows", []) - center_cols = set(d.get("center_cols", [0])) - rows = len(data) + 1 - # 알람표는 top=2.45(주의 배너 아래)에서 시작하므로 상한이 L_table보다 낮다. - _ALARM_MAX_H = 4.55 # footer y(7.05) - table top(2.45) - margin(0.05) - tbl_h = min(0.5 * rows, _ALARM_MAX_H) - tbl = s.shapes.add_table(rows, len(headers), Inches(0.55), Inches(2.45), - Inches(11.4), Inches(tbl_h)).table - for c, w in enumerate(widths): - tbl.columns[c].width = Inches(w) - for c, hd in enumerate(headers): - cell = tbl.cell(0, c) - cell.fill.solid() - cell.fill.fore_color.rgb = ACCENT - _fill_cell(cell, hd, 12, True, WHITE, center=True) - for r, row in enumerate(data, start=1): - for c, val in enumerate(row): - cell = tbl.cell(r, c) - cell.fill.solid() - cell.fill.fore_color.rgb = BG_SOFT if r % 2 == 0 else WHITE - _fill_cell(cell, val, 11, False, INK, center=(c in center_cols)) - add_logo(s) - footer(s, d.get("page"), d.get("doc_title", "")) - return s - - -BUILDERS = { - "cover": L_cover, "history": L_history, "agenda": L_agenda, "divider": L_divider, - "content": L_content, "flow": L_flow, "table": L_table, "closing": L_closing, - "screen_guide": L_screen_guide, "procedure": L_procedure, - "icon_ref": L_icon_ref, "alarm": L_alarm, -} - - -def build(spec, out_path): - prs = Presentation() - prs.slide_width = EMU_W - prs.slide_height = EMU_H - # 슬라이드 마스터 배경 적용 (흰 배경 + Ubisam 워터마크 + accent 바) - _apply_master_background(prs) - doc_title = spec.get("doc_title", "") - page = 0 - for sl in spec["slides"]: - t = sl["type"] - if t not in BUILDERS: - raise ValueError("unknown slide type: " + t) - sl.setdefault("doc_title", doc_title) - if t in ("history", "agenda", "content", "flow", "table", - "screen_guide", "procedure", "icon_ref", "alarm"): - page += 1 - sl.setdefault("page", page) - BUILDERS[t](prs, sl) - prs.save(out_path) - return len(prs.slides._sldIdLst) - - -def sample_spec(): - return { - "doc_title": "P-PRJ BFHB SW 설계서", - "slides": [ - {"type": "cover", "tag": "SW DESIGN DOCUMENT", "title": "P-PRJ BFHB SW 설계서", - "subtitles": ["인도향 P-Project · HFHB (Button Flex Hot Bar 열압착 본딩기)", - "A device that compresses a button flex by applying pressure and temperature to a point"], - "team": "{조직명}", - "contacts": ["{담당자1} {직급} {email1}", "{담당자2} {직급} {email2}"]}, - {"type": "history", "rows": [ - ["1", "1.0", "2025.04.28", "{작성자}", "초안 작성"], - ["2", "1.1", "2025.04.29", "{작성자}", "UI 안, Class 내용 추가"], - ["3", "1.2", "2025.05.09", "{작성자}", "250425_엑추에이터 정리.xlsx 내용 반영"], - ["4", "1.3", "{YYYY.MM.DD}", "{작성자}", "{변경 내용}"], - ["5", "1.4", "{YYYY.MM.DD}", "{작성자}", "{변경 내용}"], - ]}, - {"type": "agenda", "items": [ - {"no": "01", "title": "System Overview", "sub": "시스템 구성도"}, - {"no": "02", "title": "UI Concept", "sub": "Main / Teaching UI 구성"}, - {"no": "03", "title": "Sequence Flowchart", "sub": "Loading · Bonding · Unloading · PDCA"}, - {"no": "04", "title": "Class 관계도", "sub": "Class Diagram"}, - {"no": "05", "title": "축 구성", "sub": "Axis Configuration"}, - {"no": "06", "title": "IO 구성", "sub": "I/O Map"}, - ]}, - {"type": "divider", "no": "01", "title": "System Overview", "subtitle": "시스템 구성도"}, - {"type": "content", "no": "02.", "title": "UI Concept", "subtitle": "Main UI 구성 1", "panels": [ - {"title": "HotBar 측정 값", "body": "선형 그래프 (최근 생산 100개 표시)"}, - {"title": "IO Monitoring", "body": "조작 버튼 / 상태 표시"}, - {"title": "CPK", "body": "막대형 그래프"}, - {"title": "OK 판정률", "body": "도넛 그래프 (Bali 수신 + 현재공정 판정)"}, - ]}, - {"type": "flow", "no": "03.", "title": "Sequence Flowchart", "subtitle": "[Loading]", - "steps": [ - {"title": "Wait (Is Loader Empty)", "code": "SendMachine_Ready", "kind": "proc"}, - {"title": "Is UpStream Ready", "code": "CHECK_UPSTREAM", "kind": "dec"}, - {"title": "Wait (Is Board Available)", "code": "BoardAvailable", "kind": "proc"}, - {"title": "Loader Conveyor On", "code": "SendStartTransport", "kind": "proc"}, - {"title": "Is TransportError", "code": "TransportError", "kind": "dec"}, - ], - "branch": {"title": "Conveyor Stop", "sub": "Sequence Stop"}}, - {"type": "table", "no": "06.", "title": "IO 구성", "subtitle": "I/O Map", - "headers": ["No.", "Type", "Address", "Signal Name", "Description"], - "widths": [0.8, 1.4, 1.7, 3.3, 4.2], "center_cols": [0, 1, 2], - "rows": [ - ["1", "DI", "X00.0", "Start_Button", "사이클 시작 입력"], - ["2", "DI", "X00.1", "Stop_Button", "사이클 정지 입력"], - ["3", "DI", "X00.2", "EMG_Stop", "비상 정지"], - ["4", "DO", "Y10.0", "Tower_Lamp_R", "경광등 적색"], - ["5", "DO", "Y10.1", "Conveyor_Run", "컨베이어 구동"], - ["6", "DO", "Y10.2", "Stopper1_Up", "스토퍼1 상승"], - ]}, - {"type": "divider", "no": "07", "title": "Operation Manual", "subtitle": "조작 매뉴얼"}, - {"type": "screen_guide", "no": "07.", "title": "화면 설명", "subtitle": "Main 운전 화면", - "caption": "Main 운전 화면 캡처", - "items": [ - {"title": "운전 상태 표시", "desc": "현재 사이클/공정 상태 램프", "pos": [0.5, 0.5]}, - {"title": "측정값 그래프", "desc": "Load Cell · 온도 실시간 추이", "pos": [3.0, 1.5]}, - {"title": "판정 결과", "desc": "OK/NG 도넛 그래프", "pos": [5.5, 2.5]}, - {"title": "조작 버튼", "desc": "Start / Stop / Reset", "pos": [1.5, 3.8]}, - {"title": "알람 표시줄", "desc": "최근 발생 알람 메시지", "pos": [4.0, 4.3]}, - ]}, - {"type": "procedure", "no": "07.", "title": "조작 절차", "subtitle": "운전 시작 순서", - "steps": [ - {"title": "전원 ON 및 초기화", "desc": "메인 전원 인가 후 [Reset] 버튼으로 장비 초기화"}, - {"title": "원점 복귀", "desc": "[Home] 버튼 선택 → 전 축 원점 복귀 완료 확인"}, - {"title": "레시피 선택", "desc": "생산 모델에 맞는 레시피 로드 및 파라미터 확인"}, - {"title": "자동 운전 시작", "desc": "[Auto] 모드 전환 후 [Start] 버튼으로 사이클 시작"}, - {"title": "운전 종료", "desc": "[Stop] 후 사이클 완료 대기 → 전원 OFF"}, - ]}, - {"type": "icon_ref", "no": "07.", "title": "버튼 설명", "subtitle": "Main UI 조작 버튼", - "items": [ - {"icon": "▶", "name": "Start", "func": "자동 운전 시작"}, - {"icon": "■", "name": "Stop", "func": "사이클 정지"}, - {"icon": "↺", "name": "Reset", "func": "알람 해제 / 초기화"}, - {"icon": "⌂", "name": "Home", "func": "전 축 원점 복귀"}, - {"icon": "≡", "name": "Recipe", "func": "레시피 관리 화면"}, - {"icon": "⚙", "name": "Setup", "func": "설정 / 파라미터"}, - ]}, - {"type": "alarm", "no": "07.", "title": "알람 및 조치 방법", "subtitle": "주요 알람 코드", - "notice": "알람 발생 시 원인 확인 후 아래 조치 방법을 순서대로 수행하십시오.", - "rows": [ - ["AL-001", "비상정지 입력", "EMG 버튼 눌림", "안전 확인 후 EMG 해제 → Reset"], - ["AL-012", "원점 복귀 실패", "센서 미감지 / 간섭", "축 위치 확인 후 수동 원점 재시도"], - ["AL-024", "Load Cell 통신 이상", "케이블 단선 / 노이즈", "커넥터 체결 확인 후 전원 재투입"], - ["AL-031", "온도 상한 초과", "Heater 과열", "설정 온도 확인 → 냉각 후 재가동"], - ]}, - {"type": "closing", "title": "Thank You", "message": "문의 사항은 아래 담당자에게 연락 바랍니다.", - "team": "{조직명}", - "contacts": ["{담당자1} {직급} {email1}", "{담당자2} {직급} {email2}"]}, - ], - } - - -def main(): - ap = argparse.ArgumentParser() - ap.add_argument("--input", help="spec JSON path (필수 — 샘플은 --showcase)") - ap.add_argument("--showcase", action="store_true", - help="번들 샘플 덱을 만든다. 타 프로젝트 예시 데이터가 들어가므로 명시할 때만 동작") - ap.add_argument("--output", required=True, help="출력 .pptx 경로") - args = ap.parse_args() - if args.input: - with open(args.input, encoding="utf-8") as f: - spec = json.load(f) - elif args.showcase: - # 샘플은 타 프로젝트 예시 데이터를 포함한다 — 명시적으로 요청할 때만 만든다. - spec = sample_spec() - else: - ap.error("--input 또는 --showcase 중 하나가 필요하다. " - "인자 없이 실행하면 타 프로젝트 샘플이 조용히 산출되므로 막는다.") - n = build(spec, args.output) - print("saved:", os.path.abspath(args.output), "slides:", n) - - -if __name__ == "__main__": - main() diff --git a/.claude/skills/ubisam-ppt-make/examples/showcase.json b/.claude/skills/ubisam-ppt-make/examples/showcase.json deleted file mode 100644 index e457581..0000000 --- a/.claude/skills/ubisam-ppt-make/examples/showcase.json +++ /dev/null @@ -1,394 +0,0 @@ -{ - "doc_title": "P-PRJ BFHB SW 설계서", - "slides": [ - { - "type": "cover", - "tag": "SW DESIGN DOCUMENT", - "title": "P-PRJ BFHB SW 설계서", - "subtitles": [ - "인도향 P-Project · HFHB (Button Flex Hot Bar 열압착 본딩기)", - "A device that compresses a button flex by applying pressure and temperature to a point" - ], - "team": "{조직명}", - "contacts": [ - "{담당자1} {직급} {email1}", - "{담당자2} {직급} {email2}" - ] - }, - { - "type": "history", - "rows": [ - [ - "1", - "1.0", - "2025.04.28", - "{작성자}", - "초안 작성" - ], - [ - "2", - "1.1", - "2025.04.29", - "{작성자}", - "UI 안, Class 내용 추가" - ], - [ - "3", - "1.2", - "2025.05.09", - "{작성자}", - "250425_엑추에이터 정리.xlsx 내용 반영" - ], - [ - "4", - "1.3", - "2025.05.15", - "{작성자}", - "[DFM]_LG PRI_V57_BFHB_1.2 내용 반영" - ], - [ - "5", - "1.4", - "2025.05.21", - "{작성자}", - "[DFM]_LG PRI_V57_BFHB_1.7 내용 반영" - ] - ] - }, - { - "type": "agenda", - "items": [ - { - "no": "01", - "title": "System Overview", - "sub": "시스템 구성도" - }, - { - "no": "02", - "title": "UI Concept", - "sub": "Main / Teaching UI 구성" - }, - { - "no": "03", - "title": "Sequence Flowchart", - "sub": "Loading · Bonding · Unloading · PDCA" - }, - { - "no": "04", - "title": "Class 관계도", - "sub": "Class Diagram" - }, - { - "no": "05", - "title": "축 구성", - "sub": "Axis Configuration" - }, - { - "no": "06", - "title": "IO 구성", - "sub": "I/O Map" - } - ] - }, - { - "type": "divider", - "no": "01", - "title": "System Overview", - "subtitle": "시스템 구성도" - }, - { - "type": "content", - "no": "02.", - "title": "UI Concept", - "subtitle": "Main UI 구성 1", - "panels": [ - { - "title": "HotBar 측정 값", - "body": "선형 그래프 (최근 생산 100개 표시)" - }, - { - "title": "IO Monitoring", - "body": "조작 버튼 / 상태 표시" - }, - { - "title": "CPK", - "body": "막대형 그래프" - }, - { - "title": "OK 판정률", - "body": "도넛 그래프 (Bali 수신 + 현재공정 판정)" - } - ] - }, - { - "type": "flow", - "no": "03.", - "title": "Sequence Flowchart", - "subtitle": "[Loading]", - "steps": [ - { - "title": "Wait (Is Loader Empty)", - "code": "SendMachine_Ready", - "kind": "proc" - }, - { - "title": "Is UpStream Ready", - "code": "CHECK_UPSTREAM", - "kind": "dec" - }, - { - "title": "Wait (Is Board Available)", - "code": "BoardAvailable", - "kind": "proc" - }, - { - "title": "Loader Conveyor On", - "code": "SendStartTransport", - "kind": "proc" - }, - { - "title": "Is TransportError", - "code": "TransportError", - "kind": "dec" - } - ], - "branch": { - "title": "Conveyor Stop", - "sub": "Sequence Stop" - } - }, - { - "type": "table", - "no": "06.", - "title": "IO 구성", - "subtitle": "I/O Map", - "headers": [ - "No.", - "Type", - "Address", - "Signal Name", - "Description" - ], - "widths": [ - 0.8, - 1.4, - 1.7, - 3.3, - 4.2 - ], - "center_cols": [ - 0, - 1, - 2 - ], - "rows": [ - [ - "1", - "DI", - "X00.0", - "Start_Button", - "사이클 시작 입력" - ], - [ - "2", - "DI", - "X00.1", - "Stop_Button", - "사이클 정지 입력" - ], - [ - "3", - "DI", - "X00.2", - "EMG_Stop", - "비상 정지" - ], - [ - "4", - "DO", - "Y10.0", - "Tower_Lamp_R", - "경광등 적색" - ], - [ - "5", - "DO", - "Y10.1", - "Conveyor_Run", - "컨베이어 구동" - ], - [ - "6", - "DO", - "Y10.2", - "Stopper1_Up", - "스토퍼1 상승" - ] - ] - }, - { - "type": "divider", - "no": "07", - "title": "Operation Manual", - "subtitle": "조작 매뉴얼" - }, - { - "type": "screen_guide", - "no": "07.", - "title": "화면 설명", - "subtitle": "Main 운전 화면", - "caption": "Main 운전 화면 캡처", - "items": [ - { - "title": "운전 상태 표시", - "desc": "현재 사이클/공정 상태 램프", - "pos": [ - 0.5, - 0.5 - ] - }, - { - "title": "측정값 그래프", - "desc": "Load Cell · 온도 실시간 추이", - "pos": [ - 3.0, - 1.5 - ] - }, - { - "title": "판정 결과", - "desc": "OK/NG 도넛 그래프", - "pos": [ - 5.5, - 2.5 - ] - }, - { - "title": "조작 버튼", - "desc": "Start / Stop / Reset", - "pos": [ - 1.5, - 3.8 - ] - }, - { - "title": "알람 표시줄", - "desc": "최근 발생 알람 메시지", - "pos": [ - 4.0, - 4.3 - ] - } - ] - }, - { - "type": "procedure", - "no": "07.", - "title": "조작 절차", - "subtitle": "운전 시작 순서", - "steps": [ - { - "title": "전원 ON 및 초기화", - "desc": "메인 전원 인가 후 [Reset] 버튼으로 장비 초기화" - }, - { - "title": "원점 복귀", - "desc": "[Home] 버튼 선택 → 전 축 원점 복귀 완료 확인" - }, - { - "title": "레시피 선택", - "desc": "생산 모델에 맞는 레시피 로드 및 파라미터 확인" - }, - { - "title": "자동 운전 시작", - "desc": "[Auto] 모드 전환 후 [Start] 버튼으로 사이클 시작" - }, - { - "title": "운전 종료", - "desc": "[Stop] 후 사이클 완료 대기 → 전원 OFF" - } - ] - }, - { - "type": "icon_ref", - "no": "07.", - "title": "버튼 설명", - "subtitle": "Main UI 조작 버튼", - "items": [ - { - "icon": "▶", - "name": "Start", - "func": "자동 운전 시작" - }, - { - "icon": "■", - "name": "Stop", - "func": "사이클 정지" - }, - { - "icon": "↺", - "name": "Reset", - "func": "알람 해제 / 초기화" - }, - { - "icon": "⌂", - "name": "Home", - "func": "전 축 원점 복귀" - }, - { - "icon": "≡", - "name": "Recipe", - "func": "레시피 관리 화면" - }, - { - "icon": "⚙", - "name": "Setup", - "func": "설정 / 파라미터" - } - ] - }, - { - "type": "alarm", - "no": "07.", - "title": "알람 및 조치 방법", - "subtitle": "주요 알람 코드", - "notice": "알람 발생 시 원인 확인 후 아래 조치 방법을 순서대로 수행하십시오.", - "rows": [ - [ - "AL-001", - "비상정지 입력", - "EMG 버튼 눌림", - "안전 확인 후 EMG 해제 → Reset" - ], - [ - "AL-012", - "원점 복귀 실패", - "센서 미감지 / 간섭", - "축 위치 확인 후 수동 원점 재시도" - ], - [ - "AL-024", - "Load Cell 통신 이상", - "케이블 단선 / 노이즈", - "커넥터 체결 확인 후 전원 재투입" - ], - [ - "AL-031", - "온도 상한 초과", - "Heater 과열", - "설정 온도 확인 → 냉각 후 재가동" - ] - ] - }, - { - "type": "closing", - "title": "Thank You", - "message": "문의 사항은 아래 담당자에게 연락 바랍니다.", - "team": "{조직명}", - "contacts": [ - "{담당자1} {직급} {email1}", - "{담당자2} {직급} {email2}" - ] - } - ] -} \ No newline at end of file diff --git a/.claude/skills/ubisam-ppt-make/reference/layout_selection.md b/.claude/skills/ubisam-ppt-make/reference/layout_selection.md deleted file mode 100644 index 1e5ce0a..0000000 --- a/.claude/skills/ubisam-ppt-make/reference/layout_selection.md +++ /dev/null @@ -1,90 +0,0 @@ -# Layout selection guide - -How to pick the right layout for a given piece of source/analysis data when -building a Ubisam SW 설계서 / HMI Manual deck. Read this before writing the spec. - -## Slide master background (유비샘 산출물 고정) - -`build()` 호출 시 자동으로 슬라이드 마스터에 배경을 적용한다. 모든 pptx에 공통 적용. - -| 요소 | 값 | 적용 범위 | -|---|---|---| -| 캔버스 배경색 | **`WHITE`** | `_apply_master_background()`가 마스터 + 전 레이아웃에 적용 (`build_deck.py:55-73`) | -| 하단 accent 바 | `ACCENT` #4A8DCB (blue), h=0.15in | 마스터 공통 장식 (y=7.35in) | - -**상속 규칙**: 마스터 배경이 이미 `WHITE`이므로 레이아웃별 배경 차이는 없다. -cover·divider·closing만 자체 full rect로 별도 색을 덮는다. -- 배경 **덮음** (자체 흰색 rect): `cover` · `divider` · `closing` -- 배경 **상속**(= 흰 배경): `history` · `agenda` · `content` · `flow` · `table` · `screen_guide` · `procedure` · `icon_ref` · `alarm` - > `BG_SOFT`(#F4F7FA)는 **배경색이 아니라 패널·표 짝수행 fill 전용**이다. - -캔버스 배경은 `build_deck.py`의 `_apply_master_background()`가 `WHITE`로 고정. spec JSON 키로 재정의되지 않는다 — -바꾸려면 `build_deck.py`를 수정해야 한다. - - -## Quick decision table - -| If the data is… | use | not | -|------------------|-----|-----| -| Document identity (title, 장비명, 담당자) | `cover` | — | -| Revision log (버전·날짜·작성자·변경내용) | `history` | `table` | -| List of sections / TOC | `agenda` | — | -| A chapter / section break | `divider` | — | -| 2–4 parallel sub-areas, each 1 line | `content` | `table` | -| Machine/SW execution sequence **with conditions/branches** | `flow` | `procedure` | -| Reference data in rows × columns (IO, 축, 스펙, 파라미터) | `table` | `content` | -| One screenshot to annotate by region | `screen_guide` | `icon_ref` | -| Ordered **human actions**, no branching | `procedure` | `flow` | -| Set of discrete buttons/icons (name + function, ≤6) | `icon_ref` | `table` | -| Faults with cause → action (+ safety) | `alarm` | `table` | -| Closing / contact | `closing` | — | - -## Per-layout: what data belongs - -### Document layouts - -- **cover** — The deliverable's identity. Fields: doc tag, 설계서/매뉴얼 title, - 장비 한/영 설명, team, 담당자 contacts. One per deck, first slide. -- **history** — Revision rows `[No, Version, 날짜, 변경자, 변경내용]`. Use only - for the change log; any other 5-column data → `table`. -- **agenda** — Up to 6 top-level sections `{no, title(EN), sub(KO)}`. Mirrors the - `divider` numbers used later. -- **divider** — Section break: big `no` + EN title + KO subtitle. No body data. -- **content** — 2–4 panels `{title, body}`, each panel one parallel facet - (e.g. UI 화면 영역, 기능 블록). Body is a one-line description, NOT a list of - rows. If you have ≥5 items or columnar data, switch to `table`. -- **flow** — Sequence steps `{title, code, kind}` where `code` is the - method/condition name and `kind` is `proc` or `dec` (decision). Add `branch` - for the fail/stop path. Use for control sequences, state machines, 공정 흐름. - If there are no conditions/branches and the actor is a person → `procedure`. -- **table** — Any structured reference data: IO map, 축 구성, 통신 스펙, 레시피 - 파라미터. Define `headers`, `widths`, `center_cols`. Keep cells short. -- **closing** — Thank-you + contacts. Last slide. - -### Manual layouts (HMI Manual / 27번) - -- **screen_guide** — Exactly ONE screen, annotated. `caption` = what the capture - shows; `items[]` = numbered callouts `{title, desc, pos:[x,y]}` where `pos` is - the marker offset (inch) inside the capture box. Use when regions of a single - image need labels. Many separate images → multiple `screen_guide` slides. -- **procedure** — Ordered operator steps `{title, desc}`. Each step is an action - the user performs in order (전원 ON → 원점 복귀 → …). No machine codes, no - branches (those belong in `flow`). Aim for 3–6 steps. -- **icon_ref** — ≤6 discrete controls `{icon, name, func}`. One card per button/ - icon with its function. For long control lists with extra columns → `table`. -- **alarm** — Troubleshooting rows `[코드, 알람명, 발생원인, 조치방법]` plus a - `notice` safety banner. Use for alarm/fault handling; pairs each fault with its - remedy. Generic specs without cause→action → `table`. - -## Disambiguation rules (the common mistakes) - -1. **procedure vs flow** — Person doing steps in order = `procedure`. Machine/SW - executing with `if`/branches/return-to = `flow`. -2. **content vs table** — ≤4 facets each described in a sentence = `content`. - Repeating records with the same columns = `table`. -3. **icon_ref vs table** — Each item is a single control with one function = - `icon_ref`. Items have multiple attributes/columns = `table`. -4. **alarm vs table** — Rows pair a problem with its corrective action (needs the - safety banner) = `alarm`. Pure reference rows = `table`. -5. **screen_guide vs icon_ref** — Annotating positions on one image = - `screen_guide`. Listing controls independent of an image = `icon_ref`. diff --git a/.claude/skills/ubisam-ppt-make/reference/layout_selection.md.jpg b/.claude/skills/ubisam-ppt-make/reference/layout_selection.md.jpg deleted file mode 100644 index d51d63c..0000000 Binary files a/.claude/skills/ubisam-ppt-make/reference/layout_selection.md.jpg and /dev/null differ diff --git a/.claude/skills/ubisam-ppt-make/생성파일/test_bg.pptx b/.claude/skills/ubisam-ppt-make/생성파일/test_bg.pptx deleted file mode 100644 index e2322d3..0000000 Binary files a/.claude/skills/ubisam-ppt-make/생성파일/test_bg.pptx and /dev/null differ diff --git a/.claude/skills/ubisam-ppt-make/생성파일/test_wm.pptx b/.claude/skills/ubisam-ppt-make/생성파일/test_wm.pptx deleted file mode 100644 index 00c66d8..0000000 Binary files a/.claude/skills/ubisam-ppt-make/생성파일/test_wm.pptx and /dev/null differ diff --git a/.claude/skills/ui_layout_image/SKILL.md b/.claude/skills/ui_layout_image/SKILL.md deleted file mode 100644 index e411345..0000000 --- a/.claude/skills/ui_layout_image/SKILL.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -name: ui_layout_image -description: UI 소스코드(예 C# WPF XAML, WinForms, Qt, HTML/CSS, Android/Flutter)를 읽어 화면의 레이아웃 구조를 분석하고, 스크린샷 없이 그리드/컨테이너 구조를 그대로 도식(wireframe mockup) 이미지로 생성해 저장한다. 필요 시 PPT/매뉴얼에 삽입. "화면 구성 이미지로 만들어줘", "XAML 보고 레이아웃 그려줘", "코드 보고 화면 도식/목업 만들어 매뉴얼에 넣어줘", "스크린샷 말고 코드로 화면 그려줘"(**`matplotlib` 필요 — 미설치면 설치 안내 후 중단**), 그리고 후속 표현("다시 그려줘", "이미지만 재생성", "그 화면만 다시") 시 사용. **대상 화면·소스가 명시되지 않으면 기동하지 않고 되묻는다** — 이 스킬은 하네스에서 유일하게 원본 문서를 직접 수정하므로 오발동 비용이 크다. 맨손 "업데이트"·"다시 실행"만으로는 고르지 않는다. ---- - -# ui_layout_image — 코드 기반 화면 레이아웃 도식 생성 스킬 - -**실행 중인 앱 스크린샷이 아니라**, UI 소스코드의 레이아웃 정의(컨테이너/그리드/컨트롤)를 읽어 -화면 구성을 도식(wireframe mockup) 이미지로 렌더링한다. 매뉴얼·산출물·문서에 삽입하기 위함. - -## 언제 쓰나 -- 앱을 띄울 수 없거나(하드웨어/시뮬 불가), 스크린샷이 부적절할 때 -- 코드만으로 "이 화면이 이렇게 생겼다"를 문서/매뉴얼에 보여줄 때 -- 여러 화면을 일관된 스타일의 도식으로 빠르게 만들 때 - -## 입력(args) 해석 -- 대상 화면(들)의 소스 파일 경로 또는 화면 이름. 비어 있으면 무엇을 그릴지 한 줄로 물어본다. -- 선택 옵션: 스타일(dark HMI / light), 출력 경로, 삽입 대상(PPTX 경로·슬라이드). - -## 동작 절차 - -### 1) UI 소스 식별 및 레이아웃 파싱 (프레임워크별) -대상 언어/프레임워크를 판별하고 **레이아웃 트리**(중첩 컨테이너 + 컨트롤 + 라벨/바인딩)를 추출한다. - -| 프레임워크 | 읽을 것 | 핵심 레이아웃 단서 | -|-----------|--------|-------------------| -| **C# WPF** (이 프로젝트 기본) | `*.xaml` | `Grid`(RowDefinitions/ColumnDefinitions, `*`/`auto`/비율), `GroupBox.Header`, `StackPanel`, `UniformGrid(Rows/Columns)`, `Button.Content`, `TextBlock.Text`, `usercontrols:UCKeyValue KeyText/Unit`, `Grid.Row/Column/ColumnSpan` | -| C# WinForms | `*.Designer.cs` | `Controls.Add`, `.Location`, `.Size`, `.Dock`, `.Text` | -| Qt | `*.ui`(XML) | ``, ``, `` | -| HTML/CSS | `*.html`/`*.css`/JSX | div 구조, flex/grid, 라벨 텍스트 | -| Android | `res/layout/*.xml` | `LinearLayout`/`ConstraintLayout`, `android:text` | -| Flutter | `*.dart` | `Row`/`Column`/`Grid`/`Container`, `Text(...)` | - -- 비율(`2*:1*` 등), 행/열 수, 헤더 텍스트, 버튼/입력칸/표 컬럼을 **코드에서 그대로** 가져온다. 임의로 지어내지 않는다. -- 바인딩(`{Binding ...}`)은 라벨/예시값으로 치환(예: "Process Running", "1234")하되 의미를 보존한다. - -### 2) 도식 이미지 렌더링 (Python · matplotlib) -- 실행: Windows에선 `py`(파이썬 런처). -- **라이브러리 가용성을 먼저 확인한다** — `matplotlib`은 이 환경에 없을 수 있다: - `PYTHONUTF8=1 py -c "import matplotlib"` → 실패하면 `py -m pip install matplotlib` 설치를 - 사용자에게 안내하고 **중단한다.** 없는 상태로 진행하면 첫 import에서 죽는다. (`Pillow`는 설치 확인됨) -- 한글 폰트: `C:\Windows\Fonts\malgun.ttf` 를 `font_manager`로 등록. -- 좌표계: `ax.set_ylim(H, 0)` 로 좌상단 원점(화면 좌표계와 동일). -- 스타일 기본값 = **dark HMI** (이 프로젝트 UI와 일치): - - 배경 `#2D2D30`, 패널 `#3E3E42`, 테두리 `#6E6E72`, 헤더바 `#007ACC`, 글자 `#DDDDDD`, - 강조버튼 보라 `#7E57C2`/파랑 `#2D6CA2`, 입력칸 `#252528`. -- 컴포넌트 헬퍼: `panel(header)`(둥근 박스+헤더바), `kv(key,val)`(키-값 입력칸), `button(text,color)`, `label`. -- **그리드 구조를 그대로**: 컬럼 비율 → 폭 배분, 행 정의(auto/`*`) → 높이 배분, GroupBox → panel, UniformGrid → 균등 분할. -- **구현체는 같은 폴더의 `render_helpers.py`다.** 처음부터 짜지 말고 이걸 임포트한다 — - `sys.path.insert(0, "<스킬폴더>")` 후 `from render_helpers import new_canvas, panel, kv, button, label, save`. - 위 팔레트 상수도 거기 들어 있어, 직접 구현하면 값이 갈라진다. -- 참고: `UnTrackedLocalFiles/`의 `gen_mockups.py`·`gen_menubar.py`는 부가 예시이며 - `.gitignore` 제외라 **clone 직후에는 없다.** 없어도 무방하다. - -### 3) 저장 -- 기본 출력: `UnTrackedLocalFiles/hmi_mockups/.png` (git 제외 위치). 다른 위치 지정 시 그곳에. -- **저장 전 폴더를 만든다** — `mkdir -p UnTrackedLocalFiles/hmi_mockups`. 이 폴더는 `.gitignore` - 대상이라 clone 직후 **없다.** 없으면 `savefig`가 `FileNotFoundError`로 죽는다. 백업 경로도 동일. -- 생성 후 Read 도구로 PNG를 열어 **시각 검증**(겹침/라벨 누락 확인). 문제 있으면 수정 후 재생성. - -### 4) (선택) 문서/PPT 삽입 -- PPTX: `python-pptx`로 대상 슬라이드의 기존 스크린샷(PICTURE)·번호 콜아웃(예 "타원*")을 제거하고 - 같은 위치/크기에 `add_picture`. 빈 콜아웃 박스도 정리. -- 검증(선택): LibreOffice(`soffice --headless --convert-to pdf`) → PyMuPDF(`fitz`)로 PNG 렌더 후 Read. - **둘 다 이 환경에 없을 수 있다** — `command -v soffice` / `py -c "import fitz"`로 확인하고, - 없으면 삽입 검증을 생략하고 보고서에 **`미검증 — soffice/fitz 부재`** 로 명시한다. 검증했다고 하지 않는다. - -### 5) 보고 -- 생성한 이미지 경로, 반영한 화면/소스, 삽입 위치를 한 줄로 요약. 코드와 다르게 추정한 부분은 명시. - -## 주의 -- 반드시 **소스코드 기준**. 실제 값이 불명확하면 라벨/예시값으로 두고 "(예시)" 표기. -- **원본 문서(PPT/Excel)를 수정하기 전에 승인을 받는다** (`rules.md` #2) — 수정할 슬라이드·시트와 - 제거·교체할 도형 목록을 먼저 제시한다. 이 스킬은 하네스에서 **유일하게 원본을 직접 고치는** 스킬이다. -- 수정 전 백업(`UnTrackedLocalFiles/...backup`). 서식 보존. -- 기존 pptx에 이미지를 삽입하는 것은 `ubisam-ppt-make`의 "python-pptx 직접 사용 금지"의 예외다 - (덱 생성이 아니라 삽입이므로). -- 생성 스크립트·중간 렌더는 `UnTrackedLocalFiles/`(커밋 제외)에 둔다. 산출물(이미지가 삽입된 문서)만 커밋. -- 제거·교체할 도형 목록은 `rules.md` #11~13 형식으로 제시한다 — 교체 대상 줄은 초록 화살표(→), - 단어 단위는 주황, 미변경은 기본색. - -## 호출 예시 -- `/ui_layout_image UCMainAutoRun.xaml 화면 도식 만들어줘` -- `/ui_layout_image Manual/Calibration 화면들 dark 스타일로 그려서 HMI Manual.pptx 슬라이드에 넣어줘` -- 자연어: "스크린샷 말고 XAML 그리드 구조 보고 화면 레이아웃 이미지로 만들어서 매뉴얼에 넣어줘" - -> 보고는 `rules.md` #11~13 출력 형식을 따르고(수정 줄=초록 화살표, 단어=주황, 미변경=기본색), -> 단계 전환마다 진행을 한 줄로 알리며(#10), 끝에 관련 `.md` 갱신 필요 여부를 묻는다(#6). diff --git a/.claude/skills/ui_layout_image/render_helpers.py b/.claude/skills/ui_layout_image/render_helpers.py deleted file mode 100644 index 26f4078..0000000 --- a/.claude/skills/ui_layout_image/render_helpers.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: utf-8 -*- -"""ui_layout_image 스킬용 렌더 헬퍼 (dark HMI 스타일). -사용 예: - PYTHONUTF8=1 py .claude/skills/ui_layout_image/render_helpers.py # 데모 1장 생성 - (셸 cwd 는 호출마다 초기화되므로 맨 파일명으로 실행하지 않는다) -실전에서는 import 하여 panel/kv/button/label 로 화면별 도식을 그린다. -""" -import os -import matplotlib -matplotlib.use("Agg") -import matplotlib.pyplot as plt -from matplotlib.patches import FancyBboxPatch, Rectangle -import matplotlib.font_manager as fm - -# ---- 한글 폰트 ---- -FONT = r"C:\Windows\Fonts\malgun.ttf" -try: - fp = fm.FontProperties(fname=FONT) - plt.rcParams["font.family"] = fp.get_name() -except Exception: - pass -plt.rcParams["axes.unicode_minus"] = False - -# ---- dark HMI 팔레트 (프로젝트 UI와 일치) ---- -BG = "#2D2D30"; PANEL = "#3E3E42"; BORDER = "#6E6E72"; HEADER = "#007ACC" -TXT = "#DDDDDD"; PURPLE = "#7E57C2"; BLUE = "#2D6CA2"; GREEN = "#2E7D32"; GRAY = "#555558" -INPUT = "#252528"; VALCOLOR = "#9CDCFE" - - -def new_canvas(w, h): - fig = plt.figure(figsize=(w / 100, h / 100), dpi=100) - ax = fig.add_axes([0, 0, 1, 1]) - ax.set_xlim(0, w); ax.set_ylim(h, 0); ax.axis("off") - ax.add_patch(Rectangle((0, 0), w, h, facecolor=BG, edgecolor="none")) - return fig, ax - - -def panel(ax, x, y, w, h, header=None, fc=PANEL): - ax.add_patch(FancyBboxPatch((x + 2, y + 2), w - 4, h - 4, boxstyle="round,pad=2", - facecolor=fc, edgecolor=BORDER, linewidth=1.2)) - if header: - ax.add_patch(Rectangle((x + 4, y + 4), w - 8, 22, facecolor=HEADER, edgecolor="none")) - ax.text(x + 12, y + 15, header, color="white", fontsize=9, fontweight="bold", va="center") - return x + 8, y + 30 - - -def label(ax, x, y, text, size=8.5, color=TXT, bold=False, ha="left"): - ax.text(x, y, text, color=color, fontsize=size, va="center", ha=ha, - fontweight=("bold" if bold else "normal")) - - -def kv(ax, x, y, w, key, val=""): - ax.text(x + w * 0.46, y, key, color=TXT, fontsize=8, va="center", ha="right") - ax.add_patch(Rectangle((x + w * 0.5, y - 9), w * 0.48, 18, facecolor=INPUT, edgecolor=BORDER, lw=0.6)) - if val: - ax.text(x + w * 0.52, y, val, color=VALCOLOR, fontsize=8, va="center", ha="left") - - -def button(ax, x, y, w, h, text, color=BLUE): - ax.add_patch(FancyBboxPatch((x, y), w, h, boxstyle="round,pad=1.5", facecolor=color, edgecolor="none")) - ax.text(x + w / 2, y + h / 2, text, color="white", fontsize=8.5, fontweight="bold", ha="center", va="center") - - -def save(fig, path): - d = os.path.dirname(path) - if d: # 파일명만 준 경우 dirname 이 '' 이라 makedirs 가 FileNotFoundError 를 낸다 - os.makedirs(d, exist_ok=True) - fig.savefig(path, facecolor=BG) - plt.close(fig) - - -if __name__ == "__main__": - fig, ax = new_canvas(600, 300) - panel(ax, 10, 10, 580, 280, "Demo Panel") - kv(ax, 30, 60, 300, "Key", "Value") - button(ax, 30, 90, 120, 28, "Run", PURPLE) - # 출력은 스킬 폴더가 아니라 SKILL.md 가 지정한 로컬 산출 폴더로 보낸다. - repo = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..")) - out = os.path.join(repo, "UnTrackedLocalFiles", "hmi_mockups", "_demo.png") - save(fig, out) - print("demo saved:", out) diff --git a/.gitignore b/.gitignore index 73450c1..c68f6b9 100644 --- a/.gitignore +++ b/.gitignore @@ -36,12 +36,22 @@ bin/ /.git.zip /.gitignore /UnTrackedLocalFiles -.claude/* -!.claude/skills/ + +# SourceBackup.bat 산출물 (소스 백업 zip) +/ILSOS_All_src_*.zip + +.claude/ +.ubisam_agent/ +/CLAUDE.md +/README.md +/rules.md .serena/ __pycache__/ *.pyc +# docs 전체 — 로컬 전용, GIT 추적 제외 +/docs/ + # 로컬 전용 Aurora 에이전트 레퍼런스 (커밋 제외) /docs/Aurora에이전트레퍼런스모음/ diff --git a/.ubisam_agent/agents/build-devops-engineer.md b/.ubisam_agent/agents/build-devops-engineer.md deleted file mode 100644 index d57a2a9..0000000 --- a/.ubisam_agent/agents/build-devops-engineer.md +++ /dev/null @@ -1,162 +0,0 @@ ---- -name: build-devops-engineer -description: ILSOS_PrismaticRD_PTOP의 빌드 최적화 및 DevOps 자동화 전문가. 멀티 구성 빌드(Debug/Release/Simulation), 의존성 관리, CI/CD 파이프라인, 빌드 산출물 최적화를 담당. ---- - -# Build/DevOps Engineer - -## 핵심 역할 - -- **멀티 구성 빌드 최적화** — Debug|x64 / Release|x64 / Simulation|x64 / UserDefineUnit|x64 구성 관리 -- **의존성 관리** — NuGet 패키지, 프로젝트 참조, 외부 DLL(AuroraDevices 등) 버전 관리 -- **CI/CD 파이프라인 설계** — 자동 빌드, 테스트, 배포 워크플로우 -- **빌드 산출물 최적화** — 출력 크기 감소, 로딩 시간 단축, 배포 패키징 - -## 작업 원칙 - -1. **ILSOS_All.sln 빌드 구조 분석** - - 솔루션의 모든 프로젝트 (Machines/, AuroraDevices/, AuroraComponents/, WeldingComponents/, etc.) - - PTOP에 필요한 의존성 (최소 빌드 집합) - - 불필요한 프로젝트 참조 제거 가능성 - -2. **빌드 구성별 설정 검토** - - Debug: 기호 생성, 최적화 비활성화 - - Release: 최적화 활성화, 기호 제거 - - Simulation: 하드웨어 통신 불필요 → 모의 디바이스 사용 - - UserDefineUnit: 커스텀 설정 (용도 파악 필요) - -3. **빌드 성능 분석** - - 현재 빌드 시간 측정 - - 병목 프로젝트 식별 (가장 느린 컴파일) - - 캐싱 활용 가능성 - -4. **의존성 버전 관리** - - NuGet 패키지 호환성 검증 - - Breaking change 감지 - - 업그레이드 경로 계획 - -5. **배포 패키징** - - 실행 가능 파일 크기 최적화 - - 필요한 DLL/리소스 파일 포함 - - 배포 스크립트 자동화 - -## 입력/출력 프로토콜 - -**입력:** -- PTOP Lead의 TaskCreate: "빌드 최적화 분석해줘", "CI/CD 파이프라인 설계" -- 팀의 빌드 이슈 보고 (SendMessage) - -**출력:** - -1. **빌드 분석 보고서** (`_workspace/04_build_analysis.md`): - ```markdown - # PTOP 빌드 최적화 분석 - - ## 현재 빌드 구성 - - Debug|x64: [빌드 시간] ms - - Release|x64: [빌드 시간] ms - - Simulation|x64: [빌드 시간] ms - - UserDefineUnit|x64: [빌드 시간] ms - - ## 의존성 분석 - | 프로젝트 | 참조 | 용도 | 최소화 가능 | - |---------|------|------|----------| - | AuroraDevices | Yes | 디바이스 제어 | No | - | ... | ... | ... | ... | - - ## 성능 병목 - 1. [프로젝트명] - [원인] - [개선안] - 2. ... - - ## 개선 방안 - - [우선순위] [설명] [예상 효과] - ``` - -2. **CI/CD 파이프라인 설계** (`_workspace/05_cicd_pipeline.yml`): - ```yaml - # 예시: GitHub Actions / Azure Pipelines - - name: PTOP Build & Test - - on: [push, pull_request] - - jobs: - build: - runs-on: windows-latest - strategy: - matrix: - config: [Debug, Release, Simulation] - steps: - - uses: actions/checkout@v2 - - name: Restore NuGet packages - - name: Build PTOP (${{ matrix.config }}) - - name: Run tests - - name: Upload artifacts - ``` - -3. **빌드 최적화 가이드** (`_workspace/06_build_optimization.md`): - ```markdown - ## 권장 빌드 설정 - - ### Release 빌드 - - 최적화 활성화 (/O2) - - 기호 제거 - - 링커 최적화 활성화 - - ### Simulation 빌드 - - 하드웨어 통신 불필요 → 조건부 컴파일 - - ## 캐싱 전략 - - NuGet cache: ~/.nuget/packages - - Build artifacts: _out_prismatic_rd_ptop - - ## 배포 체크리스트 - - [ ] 모든 DLL 포함 - - [ ] 구성 파일 (app.config) 포함 - - [ ] 리소스 파일 포함 - ``` - -4. **SendMessage to PTOP Lead**: - - 빌드 분석 완료 알림 - - 주요 성능 병목 - - 권장 개선 우선순위 - - CI/CD 자동화 일정 - -## 에러 핸들링 - -- 빌드 실패 시 → 정확한 오류 메시지와 해결 방법 기록 -- 의존성 충돌 발견 시 → 버전 호환성 분석 및 해결책 제시 -- 성능 개선 효과 측정 불가능 시 → "측정 필요" 표시 - -## 팀 통신 프로토콜 - -**상급자:** PTOP Lead - -**역할:** -- PTOP Lead의 지시에 따라 빌드 최적화 수행 -- 분석 결과를 _workspace 파일로 저장 -- SendMessage로 PTOP Lead에 진행상황 보고 -- 빌드 관련 이슈 발견 시 즉시 팀에 알림 - -**기여:** -- 빌드 시간 단축 → 개발 생산성 향상 -- 배포 패키징 자동화 → 릴리스 안정성 -- CI/CD 파이프라인 → 지속적 검증 - -## 성공 기준 - -- [ ] 4가지 빌드 구성의 현재 시간이 측정되고 문서화됨 -- [ ] PTOP 필수 의존성이 명확히 파악됨 -- [ ] 제거 가능한 의존성이 식별됨 -- [ ] 빌드 병목이 파악되고 개선안이 제시됨 -- [ ] CI/CD 파이프라인 설계가 완료됨 (YAML/JSON 형식) -- [ ] 배포 패키징 자동화 스크립트가 작성됨 -- [ ] 빌드 최적화의 예상 효과가 정량화됨 (시간, 크기 등) -- [ ] 모든 구성에서 빌드 성공 확인됨 - -## 보충: 추천 도구 & 기술 - -- **빌드 도구**: MSBuild, NuGet -- **CI/CD**: GitHub Actions, Azure Pipelines, Jenkins -- **성능 분석**: PDBs, WinDbg, ETW -- **패키징**: NSIS, WiX, Chocolatey diff --git a/.ubisam_agent/agents/ptop-developer.md b/.ubisam_agent/agents/ptop-developer.md deleted file mode 100644 index 6045f2e..0000000 --- a/.ubisam_agent/agents/ptop-developer.md +++ /dev/null @@ -1,121 +0,0 @@ ---- -name: ptop-developer -description: ILSOS_PrismaticRD_PTOP의 구현 전문가. SeqAutoRunPTOP 시퀀스 로직, PLC/IO/Laser/OCT/CellTracker 디바이스 통합, Rx.NET 이벤트 흐름을 분석하고 개선/확장 방안을 제시. ---- - -# PTOP Developer - -## 핵심 역할 - -- **시퀀스 구현 분석** — SeqAutoRunPTOP, SeqAutoRunComponentWeld 등의 상태 머신, 타이밍, 에러 처리 -- **디바이스 통합** — PLC, IO, Laser, OCT, CellTracker의 호출 흐름 및 동기화 -- **Rx.NET 이벤트 체인** — 메시지 발행-구독 패턴, 스트림 처리, 에러 전파 -- **구현 개선안 제시** — 코드 단순화, 버그 식별, 성능 최적화 - -## 작업 원칙 - -1. **SeqAutoRunPTOP.cs 심층 분석** - - 상태 머신 정의 (시작 → 준비 → 용접 → 완료 → 복구) - - 각 상태의 진입/종료 조건 - - 타임아웃, 재시도, 폴백 로직 - - 디바이스 호출 시점과 순서 - -2. **Device/ 폴더 전체 숙지** - - PLCController.Config.cs — PLC 주소 맵핑 - - PLCController.Logic.cs — PLC 읽기/쓰기 로직 - - PLCController.Address.cs — 신호 상수 - - PAIX_PrismaticScanner.cs — IO 제어 - -3. **Rx.NET 메시지 흐름** - - System.Reactive 구독 패턴 추적 - - 메시지 타입 (String/Double/Int/JSON/LBAD) - - 에러 처리 (OnError, Catch) - - 백프레셔(Backpressure) 관리 - -4. **Laser + OCT + CellTracker 통합** - - 각 디바이스의 초기화, 활성화, 비활성화 시점 - - 순차 실행 vs 병렬 실행 여부 - - 디바이스 간 신호 의존성 - -5. **Test 시퀀스 이해** (SeqTestRun, SeqStreamTest, SeqEventQTest) - - 각 테스트의 목적 - - 메인 시퀀스와의 관계 - - 디버깅/검증에 사용 가능성 - -## 입력/출력 프로토콜 - -**입력:** -- PTOP Lead의 TaskCreate: "시퀀스 구현 분석해줘", "PLC 통신 흐름 추적" -- PTOP Lead의 SendMessage: "이 부분이 명확하지 않은데 확인해줄 수 있나?" - -**출력:** - -1. **시퀀스 분석 보고서** (`_workspace/02_ptop_sequence_analysis.md`): - ```markdown - # SeqAutoRunPTOP 분석 - - ## 상태 머신 - - State 정의 - - 전이 조건 - - 타임아웃 설정 - - ## 디바이스 호출 순서 - 1. PLC.xxx() 호출 - 2. Laser.xxx() 호출 - 3. OCT 스캔 - 4. ... - - ## 에러 처리 - - TimeoutException 처리 - - PLC 오류 대응 - - 복구 절차 - - ## 개선 사항 - - [우선순위] [설명] - ``` - -2. **디바이스 통합 맵핑** (`_workspace/03_device_integration.md`): - ```markdown - | 시퀀스 단계 | PLC 신호 | Laser | OCT | CellTracker | 타이밍 | - |-----------|---------|-------|-----|------------|--------| - | 시작 | Ready | - | - | - | T+0ms | - | 준비 | Setup | Standby | Init | Track | T+100ms | - | ... | ... | ... | ... | ... | ... | - ``` - -3. **SendMessage to PTOP Lead**: - - 분석 완료 알림 - - 주요 발견사항 - - 불명확한 부분 목록 - - 개선 우선순위 - -## 에러 핸들링 - -- 코드를 못 찾을 경우 → 정확한 파일 경로/라인 번호를 PTOP Lead에 요청 -- 로직이 이해 안 될 경우 → "이 부분은 왜 이렇게 하는 걸까?" 질문을 문서에 명시 -- 디바이스 호출 순서가 불명확할 경우 → 타이밍 다이어그램으로 시각화 - -## 팀 통신 프로토콜 - -**상급자:** PTOP Lead - -**역할:** -- PTOP Lead의 지시를 받아 구현 분석 수행 -- 분석 결과를 _workspace 파일로 저장 -- SendMessage로 PTOP Lead에 진행상황 보고 -- 불명확한 부분은 PTOP Lead에 질의 - -**기여:** -- 구현 단계 문제 조기 발견 -- 코드 품질 정보 (복잡도, 버그 가능성) -- 성능/안정성 개선안 - -## 성공 기준 - -- [ ] SeqAutoRunPTOP의 상태 머신이 명확한 다이어그램으로 표현됨 -- [ ] 모든 주요 디바이스 호출(PLC, Laser, OCT, CellTracker)이 타이밍과 함께 기록됨 -- [ ] 각 시퀀스 단계의 예상 소요시간이 문서화됨 -- [ ] 에러 케이스(TimeoutException, 디바이스 오류) 처리 방식이 명확함 -- [ ] Rx.NET 메시지 흐름이 파이프라인으로 표현됨 -- [ ] 발견된 구현 문제/개선 사항이 우선순위와 함께 나열됨 -- [ ] 코드의 복잡한 부분(예: 동기화, 폴백)이 설명됨 diff --git a/.ubisam_agent/agents/ptop-lead.md b/.ubisam_agent/agents/ptop-lead.md deleted file mode 100644 index cf309bd..0000000 --- a/.ubisam_agent/agents/ptop-lead.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -name: ptop-lead -description: ILSOS_PrismaticRD_PTOP 프로젝트의 아키텍처 리더. 최신 PTOP 시퀀스(SeqAutoRunPTOP.cs, 260605)를 중심으로 전체 구조 설계, 팀 조율, 공유 컴포넌트(PLC, IO, Laser, OCT, CellTracker) 통합을 담당. ---- - -# PTOP Lead (Architecture) - -## 핵심 역할 - -- **PTOP 전체 아키텍처 설계 및 검토** — 3계층(UI → Machine Logic → Device) 구조 검증 -- **팀 리더십** — 4명 팀원 작업 조율, 의존성 관리, 상충 해결 -- **시퀀스-디바이스 통합** — SeqAutoRunPTOP과 PLC/IO/Laser 간 상호작용 검증 -- **구현 진행 상황 추적** — 260605 이후 변경사항, 진행중인 기능 파악 - -## 작업 원칙 - -1. **ILSOS_PrismaticRD_PTOP 전체 파악** - - EquipDef.cs → EquipmentSetup.cs → Sequences/ → Device/ 통합 흐름 - - 네임스페이스가 ILSOS_PrismaticScanner이지만 실제로 PTOP 모듈임을 이해 - - SeqAutoRunPTOP.cs(260605)가 메인 시퀀스임을 중심으로 - -2. **시퀀스 인벤토리** - - SeqAutoRunPTOP (메인) - - SeqAutoRunPrismaticScanner (기존, 아직 존재) - - SeqAutoRunComponentWeld - - SeqTestRun, SeqStreamTest, SeqEventQTest - - 각 시퀀스의 활성 상태, 의존성 파악 - -3. **디바이스 스택** - - PLC (Mitsubishi) - 주요 제어 - - IO (PAIX_PrismaticScanner.cs) - - Laser (AuroraLaser) - - OCT Scanner (AuroraOCT) - - CellTracker (AuroraCellTracker) - - 각 디바이스의 초기화, 통신, 에러 처리 흐름 - -4. **의존성 맵핑** - - WeldingCommon (공유 라이브러리) - - AuroraDevices (드라이버) - - System.Reactive (이벤트 기반) - -5. **빌드 구성 이해** - - Debug/Release/Simulation/UserDefineUnit 중 PTOP에 적용되는 것 - - 빌드 출력 (_out_prismatic_rd_ptop) - -## 입력/출력 프로토콜 - -**입력:** -- 사용자: "PTOP 아키텍처 검토", "PTOP 시퀀스-디바이스 흐름 분석" -- 팀원들의 분석 결과 (SendMessage) - -**출력:** -- **PTOP 아키텍처 검토 보고서** (`_workspace/01_ptop_architecture.md`): - - [ ] 3계층 아키텍처 다이어그램 - - [ ] SeqAutoRunPTOP 메인 흐름도 - - [ ] 디바이스 스택 매핑 (PLC, IO, Laser, OCT, CellTracker) - - [ ] 시퀀스 의존성 그래프 - - [ ] Rx.NET 메시지 흐름 - - [ ] 발견된 개선 사항 (우선순위) - -- **팀 회의 진행 현황** (SendMessage로 각 팀원과 통신) - -## 에러 핸들링 - -- 코드 구조가 불명확할 경우 → 해당 Specialist에게 심층 분석 요청 -- 디바이스 간 상충 발견 → 양쪽 분석 결과를 병기하고 리뷰 회의 제안 -- 시퀀스-디바이스 연결이 찾기 어려울 경우 → "이 신호는 어디서 올까?" 질문을 팀에 공개 - -## 팀 통신 프로토콜 - -**팀 구성원:** -- PTOP Sequence Specialist (시퀀스 분석) -- PTOP Device/PLC Expert (디바이스 분석) -- DevOps Engineer (빌드/배포 분석) - -**발신 메시지:** - -1. **TaskCreate** — 초기 작업 할당 - ``` - [Task: Sequence Analysis] - SeqAutoRunPTOP.cs의 상태 머신, 타이밍, 디바이스 호출 분석 - 결과를 _workspace/02_ptop_sequences.md에 저장 후 SendMessage - ``` - -2. **SendMessage** — 진행 중 질문, 상충 해결 - ``` - [Q] SeqAutoRunPTOP에서 PLC.xxxx() 호출 시점이 명확하지 않습니다. - Device Expert의 분석과 함께 설명해주실 수 있나요? - ``` - -3. **TaskUpdate** — 작업 진행상황 추적 - -**수신 대기:** -- 각 Specialist의 분석 결과 (SendMessage) -- 분석 완료 후 _workspace 파일 생성 - -## 성공 기준 - -- [ ] PTOP 전체 아키텍처가 명확하게 문서화됨 (다이어그램 포함) -- [ ] SeqAutoRunPTOP의 상태 머신이 이해됨 -- [ ] 모든 주요 디바이스(PLC, IO, Laser, OCT, CellTracker)의 역할이 파악됨 -- [ ] 각 시퀀스(Auto/Component/Test)의 목적과 의존성이 명확함 -- [ ] Rx.NET 메시지 흐름이 예시화됨 -- [ ] 발견된 개선 사항이 우선순위와 함께 나열됨 -- [ ] 팀원 모두 PTOP 구조에 대해 같은 이해를 공유함 diff --git a/.ubisam_agent/settings.json b/.ubisam_agent/settings.json deleted file mode 100644 index 6f7f77e..0000000 --- a/.ubisam_agent/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "enabledPlugins": { - "harness@harness-marketplace": true, - "serena@claude-plugins-official": true - } -} diff --git a/.ubisam_agent/skills/analyze-ptop-architecture/SKILL.md b/.ubisam_agent/skills/analyze-ptop-architecture/SKILL.md deleted file mode 100644 index 765d0c6..0000000 --- a/.ubisam_agent/skills/analyze-ptop-architecture/SKILL.md +++ /dev/null @@ -1,210 +0,0 @@ ---- -name: analyze-ptop-architecture -description: ILSOS_PrismaticRD_PTOP의 3계층 아키텍처(UI → Machine Logic → Device)를 분석하고 검증. EquipDef.cs, EquipmentSetup.cs, Sequences/, Device/ 폴더의 관계를 맵핑하고 Rx.NET 이벤트 흐름을 추적. 디바이스 스택(PLC, Laser, OCT, CellTracker) 통합 여부 검증. PTOP 아키텍처를 이해하거나 설계해야 할 때, "PTOP 아키텍처 분석", "PTOP 구조 검토", "PTOP 전체 흐름 파악" 요청 시 반드시 이 스킬을 사용. ---- - -# Analyze PTOP Architecture Skill - -## 목표 - -ILSOS_PrismaticRD_PTOP의 **3계층 아키텍처 전체 그림**을 명확히 파악하고 문서화한다. - -## 분석 단계 - -### 1단계: EquipDef.cs & EquipmentSetup.cs 분석 - -**EquipDef.cs에서 수집할 항목:** -- `CommonDeviceIds` 상속 항목 (MassFlowMeter 등) -- `CommonSequenceIds` 상속 항목 (SeqStreamTest, SeqEventQTest, SeqTestRun, SeqAutoRunComponentWeld, SeqAlarmMonitor, SeqStatusMonitor, SeqAutoRunPTOP) -- 커스텀 DeviceIds, SequenceIds, MotorIds - -**EquipmentSetup.cs에서 수집할 항목:** -- `GetEquipmentName()` → 장비명 확인 ("ILSOS PrismaticRD_PTOP") -- `BuildMainStatusView()` → 표시되는 디바이스 (CellTracker, OCT) -- `OnSetAlarm()` 로직 → 알람 처리 -- `OnStartUp()` 로직 → 초기화 순서 -- SequenceBuilder 선언 → 실제 빌드되는 시퀀스 - - `_SeqAutoRunPrismaticScanner_Builder` - - `_SeqAutoRunComponentWeld_Builder` - - `_SeqTestRun_Builder` - - `_SeqAlarmMonitor_Builder` - - `_SeqAutoRunPTOP_Builder` ← 메인 시퀀스 (260605) - -**출력:** `_workspace/01a_equipdef_analysis.md` - -### 2단계: Sequences/ 폴더 구조 분석 - -**주요 파일들:** -``` -Sequences/ -├── SeqAutoRunPTOP.cs ← 메인 (분석 우선순위 1) -├── SeqAutoRunPrismaticScanner.cs -├── SeqAutoRunComponentWeld.cs -├── SeqTestRun.cs -├── SeqStreamTest.cs -├── SeqEventQTest.cs -├── SequenceContextEx.cs ← 컨텍스트 정의 -├── SequenceManager.cs ← 시퀀스 관리 -├── Monitoring/ -│ ├── SeqAlarmMonitor.cs -│ └── SeqStatusMonitor.cs -└── Manual/ - └── SeqComponentTeachingRun.cs -``` - -**각 시퀀스 분석 항목:** -- 용도 (주 시퀀스? 테스트? 모니터링?) -- 상태 머신 정의 (시작, 대기, 실행, 완료, 에러) -- 타이밍 (예상 소요시간) -- 호출하는 디바이스 목록 -- 의존성 (다른 시퀀스에 의존하는가?) - -**특히 SeqAutoRunPTOP.cs:** -- 상태 다이어그램 작성 -- 각 상태에서 호출되는 디바이스/API 추적 -- 타임아웃/재시도 로직 - -**출력:** `_workspace/01b_sequences_analysis.md` - -### 3단계: Device/ 폴더 분석 - -**파일 구조:** -``` -Device/ -├── PLC/ -│ ├── PLCController.Config.cs ← PLC 주소 맵핑 -│ ├── PLCController.Logic.cs ← 읽기/쓰기 로직 -│ └── PLCController.Address.cs ← 신호 상수 -└── IO/ - └── PAIX_PrismaticScanner.cs ← IO 제어 -``` - -**PLC 분석:** -- 사용되는 주소 범위 (예: M0~M100, D0~D500) -- 주요 신호 목록 (Ready, Setup, Error, etc.) -- 읽기 주기, 쓰기 주기 -- 타임아웃 설정 - -**IO 분석:** -- 입력 신호 (센서, 스위치) -- 출력 신호 (제어 신호) -- 각 신호의 의미 - -**출력:** `_workspace/01c_device_analysis.md` - -### 4단계: Rx.NET 이벤트 흐름 분석 - -**수집할 정보:** -- System.Reactive 사용 패턴 (Observable, Subject, etc.) -- 메시지 타입 (String/Double/Int/JSON/LBAD) -- 구독자 목록 (누가 어떤 메시지를 구독?) -- 백프레셔/에러 처리 - -**파이프라인 예시:** -``` -[PLC Status] Observable - ├─→ Filter(Ready == true) - ├─→ Select(x => new LaserCommand()) - └─→ Subscribe(Laser.Execute()) -``` - -**출력:** `_workspace/01d_rxnet_analysis.md` - -### 5단계: 외부 디바이스 통합 검증 - -**검증 대상:** -- PLC (Mitsubishi) -- Laser (AuroraLaser) -- OCT Scanner (AuroraOCT) -- CellTracker (AuroraCellTracker) -- IO (PAIX) - -**각 디바이스마다:** -- 초기화 시점 -- 활성화 조건 -- 사용 방식 (동기/비동기) -- 에러 처리 -- 정상 종료 절차 - -**출력:** `_workspace/01e_device_integration.md` - -## 통합 산출물 - -### 최종 보고서: `_workspace/01_ptop_architecture.md` - -```markdown -# ILSOS_PrismaticRD_PTOP 아키텍처 검토 보고서 - -## 1. 3계층 아키텍처 - -``` -┌──────────────────────────────┐ -│ WPF UI Layer │ -│ (Views/, ViewModels/) │ -└──────────────┬───────────────┘ - ↓ -┌──────────────────────────────┐ -│ Machine Logic Layer │ -│ (EquipmentSetup, Sequences) │ -└──────────────┬───────────────┘ - ↓ -┌──────────────────────────────┐ -│ Device Abstraction │ -│ (AuroraDevices) │ -└──────────────┬───────────────┘ - ↓ -┌──────────────────────────────┐ -│ Hardware Layer │ -│ (PLC, Laser, OCT, etc.) │ -└──────────────────────────────┘ -``` - -## 2. 핵심 컴포넌트 - -### EquipDef & EquipmentSetup -- [EquipDef 매핑 표] -- [빌드되는 시퀀스 목록] - -### Sequences -- [시퀀스 관계도] -- [SeqAutoRunPTOP 상태 머신] - -### Device -- [PLC 신호 맵핑] -- [IO 신호 맵핑] - -## 3. Rx.NET 이벤트 흐름 - -[파이프라인 다이어그램] - -## 4. 발견 사항 & 개선 사항 - -| 우선순위 | 항목 | 현황 | 개선안 | -|---------|------|------|--------| -| P0 | | | | -| P1 | | | | - -``` - -## 입력 조건 - -사용자가 다음과 같이 요청할 때: -- "PTOP 아키텍처 분석해줘" -- "PTOP 전체 구조 파악" -- "SeqAutoRunPTOP이 어떻게 동작하는지 분석" -- "PTOP에서 PLC, Laser, OCT가 어떻게 연결되어있는지" -- "PTOP 3계층 아키텍처 검증" - -## 출력 결과 - -- 5개 상세 분석 문서 (`_workspace/01a~01e_*.md`) -- 통합 보고서 (`_workspace/01_ptop_architecture.md`) -- 다이어그램 (3계층, 상태 머신, 이벤트 흐름) - -## 주의사항 - -1. **코드 읽기 능력이 중요** — C#, WPF, Rx.NET 이해 필수 -2. **불명확한 부분은 기록** — "이 부분은 왜 이렇게?"라는 질문을 명시 -3. **Namespace 혼동 주의** — ILSOS_PrismaticRD_PTOP의 코드가 ILSOS_PrismaticScanner 네임스페이스 사용 -4. **260605 변경 이후 상태 파악** — SeqAutoRunPTOP이 최신 메인 시퀀스 -5. **한글 주석 인코딩** — CODING_RULES.md 확인 diff --git a/.ubisam_agent/skills/analyze-ptop-implementation/SKILL.md b/.ubisam_agent/skills/analyze-ptop-implementation/SKILL.md deleted file mode 100644 index 2cde25a..0000000 --- a/.ubisam_agent/skills/analyze-ptop-implementation/SKILL.md +++ /dev/null @@ -1,209 +0,0 @@ ---- -name: analyze-ptop-implementation -description: ILSOS_PrismaticRD_PTOP의 구현 상세 분석. SeqAutoRunPTOP 시퀀스 로직, PLC/Laser/OCT/CellTracker 디바이스 호출 흐름, Rx.NET 메시지 체인, 상태 전이, 타이밍, 에러 처리를 분석하고 구현 개선안 제시. "PTOP 시퀀스 로직 분석", "PLC 통신 흐름 추적", "디바이스 호출 순서", "타이밍 다이어그램" 요청 시 사용. ---- - -# Analyze PTOP Implementation Skill - -## 목표 - -ILSOS_PrismaticRD_PTOP의 **구현 세부사항**을 분석하고 최적화 기회를 식별한다. - -## 분석 영역 - -### 1단계: SeqAutoRunPTOP.cs 상태 머신 분석 - -**수집 대상:** -- 상태 정의 (enum/class로 표현된 상태들) -- 상태 진입 조건 -- 상태 내 액션 (동작) -- 상태 종료 조건 -- 상태 전이 경로 -- 타임아웃 설정 -- 재시도 로직 - -**산출 형식: 상태 다이어그램** -``` -[시작] - ↓ (T+0ms) -[초기화] → [준비] → [용접] → [완료] → [정리] → [대기] - ↓ ↓ ↓ ↓ ↓ -[에러 처리] ← ← ← ← ← ← ← ← ← ← ← ← -``` - -### 2단계: 디바이스 호출 시퀀스 추적 - -각 상태에서: -- 어떤 디바이스가 호출되는가? -- 호출 순서는? (순차 vs 병렬) -- 예상 소요시간? -- 다음 상태로의 전이 신호는 어디서 오는가? - -**추적 대상:** -1. **PLC 호출** - - 읽기: PLC.ReadBool("M10"), PLC.ReadInt("D20"), etc. - - 쓰기: PLC.WriteBool("M5", true), PLC.WriteInt("D15", 100), etc. - - 대기: PLC 상태 폴링, 신호 기다리기 - -2. **Laser 제어** - - 활성화 (SetPower, SetFrequency, etc.) - - 대기 - - 정상 종료 - -3. **OCT 스캔** - - 스캔 시작 - - 데이터 수집 - - 스캔 종료 - -4. **CellTracker** - - 셀 추적 시작 - - 위치 업데이트 - - 추적 종료 - -**산출 형식: 타이밍 다이어그램** -``` -Time(ms) 0 100 200 300 400 500 -State [INIT][PREP][WELD..................][DONE] -PLC ReadM10 ----WriteM5---- ReadM10 -Laser ----SetPower-----------SetPower(0) -OCT --------Scan Start----Scan End -CellTrk ----Start----Update--Update--Stop -``` - -### 3단계: Rx.NET 메시지 체인 분석 - -**수집 대상:** -- Observable 소스 (어디서 데이터가 나오는가?) -- 변환 (Select, Map, Filter) -- 구독자 (누가 소비하는가?) -- 에러 처리 (OnError, Catch) - -**예시:** -```csharp -// PLC 상태를 구독하여 Laser 제어 -AuroraEnv.MessageQueue - .Where(msg => msg.Key == "PLC_Status") - .DistinctUntilChanged() - .Subscribe(msg => - { - if (msg.Value == "Ready") { - Laser.SetPower(100); - } - }); -``` - -**산출 형식: 메시지 파이프라인 맵** - -### 4단계: 에러 처리 로직 - -**찾아야 할 패턴:** -- Try-Catch 블록 -- TimeoutException 처리 -- PLC 에러 응답 처리 -- 디바이스 오류 복구 -- 폴백 경로 (재시도, 초기화 재개, 강제 종료) - -**각 에러에 대해:** -- 감지 방법 -- 처리 방식 -- 복구 가능 여부 -- 사용자 개입 필요 여부 - -### 5단계: 성능/안정성 분석 - -**성능:** -- 각 상태의 예상 소요시간 -- 전체 시퀀스 총 소요시간 -- 병목 구간 (가장 오래 걸리는 부분) -- 최적화 기회 (병렬화 가능한가?) - -**안정성:** -- 데드락 가능성 (두 디바이스가 서로 대기?) -- 타이밍 이슈 (신호 도착 순서 의존?) -- 리소스 누수 (구독 취소 안 됨?) -- 상태 불일치 (PLC와 소프트웨어 상태 차이?) - -## 통합 산출물 - -### 최종 보고서: `_workspace/02_ptop_implementation.md` - -```markdown -# PTOP 구현 분석 보고서 - -## 1. 상태 머신 - -[다이어그램] - -## 2. 디바이스 호출 시퀀스 - -### 시작 → 준비 전이 -- T+0ms: PLC ReadBool("M10", Ready) 확인 -- T+50ms: Laser SetPower(100) 호출 -- T+100ms: OCT Scan Start -- 조건: 모든 디바이스 Ready ⇒ 다음 상태로 전이 - -[세부 타이밍 테이블] - -## 3. Rx.NET 메시지 흐름 - -``` -PLC Status Observable - └─ Filter(Ready) - └─ Select(→ LaserCommand) - └─ Subscribe(Laser.Execute) -``` - -## 4. 에러 처리 - -| 에러 유형 | 감지 방법 | 처리 방식 | 복구 가능 | -|---------|---------|---------|---------| -| PLC Timeout | ReadBool() 예외 | 재시도 3회 | Yes | -| Laser Error | Laser.Status != OK | 전원 차단 후 재시작 | Yes | -| ... | ... | ... | ... | - -## 5. 성능 프로파일 - -| 구간 | 소요시간 | 최적화 기회 | -|------|---------|----------| -| 준비 단계 | 200ms | 병렬화 불가 | -| 용접 단계 | 1500ms | OCT 스캔 시간 단축? | -| ... | ... | ... | - -## 6. 발견 사항 - -### P0 (심각) -- [내용] - -### P1 (중요) -- [내용] - -### P2 (개선) -- [내용] - -``` - -## 입력 조건 - -사용자가 다음 요청 시: -- "PTOP 시퀀스 로직 상세 분석" -- "SeqAutoRunPTOP이 PLC/Laser/OCT을 어떻게 제어하는가" -- "PTOP 타이밍 분석" -- "PTOP에서 에러가 발생하면 어떻게 처리되나" -- "PTOP의 성능 병목은" - -## 출력 결과 - -- 상태 머신 다이어그램 -- 타이밍 다이어그램 (시간축) -- Rx.NET 메시지 흐름도 -- 에러 처리 매트릭스 -- 성능 프로파일 -- 최종 분석 보고서 - -## 주의사항 - -1. **코드 라인 번호 기록** — "Line 245의 try-catch" 형식으로 정확한 위치 기록 -2. **데이터 흐름 추적** — 변수, 반환값을 따라가며 이해 -3. **시간 측정** — Thread.Sleep() / Task.Delay() / TimeSpan 찾기 -4. **예외 처리** — Exception 타입별로 분류 -5. **불명확한 부분 기록** — 추측 금지, 명시적으로 "불명확함" 표시 diff --git a/.ubisam_agent/skills/optimize-ptop-build/SKILL.md b/.ubisam_agent/skills/optimize-ptop-build/SKILL.md deleted file mode 100644 index 1a2f843..0000000 --- a/.ubisam_agent/skills/optimize-ptop-build/SKILL.md +++ /dev/null @@ -1,248 +0,0 @@ ---- -name: optimize-ptop-build -description: ILSOS_PrismaticRD_PTOP의 빌드 최적화 및 CI/CD 자동화. 멀티 구성 빌드(Debug/Release/Simulation/UserDefineUnit) 분석, 의존성 최적화, 빌드 시간 단축, CI/CD 파이프라인 설계. "빌드 최적화", "PTOP 빌드 성능", "CI/CD 자동화 설계", "배포 파이프라인" 요청 시 사용. ---- - -# Optimize PTOP Build Skill - -## 목표 - -ILSOS_PrismaticRD_PTOP의 **빌드 성능 및 자동화**를 최적화한다. - -## 분석 영역 - -### 1단계: 현재 빌드 상태 분석 - -**수집 대상:** -- 솔루션 내 프로젝트 목록 (ILSOS_All.sln) -- PTOP이 참조하는 프로젝트 -- 각 프로젝트의 빌드 시간 측정 - -**측정 방법:** -```powershell -# Visual Studio 빌드 시간 측정 -msbuild ILSOS_All.sln /p:Configuration=Release /p:Platform=x64 /d:MSBUILDENABLEALLPROJECTSBUILDFASTPATH=true - -# 또는 개별 구성별 -msbuild ILSOS_All.sln /p:Configuration=Simulation /p:Platform=x64 -``` - -**수집 항목:** -| 구성 | 총 소요시간 | 병목 프로젝트 (상위 3) | 캐시 효율 | -|------|-----------|------------------|---------| -| Debug|x64 | ? | ? | ? | -| Release|x64 | ? | ? | ? | -| Simulation|x64 | ? | ? | ? | -| UserDefineUnit|x64 | ? | ? | ? | - -### 2단계: 의존성 분석 - -**PTOP의 최소 필수 의존성 파악:** - -``` -ILSOS_PrismaticRD_PTOP -├── WeldingCommon (필수) -├── WeldingComponents (필수) -│ ├── WeldingCommon.dll -│ ├── LASAGUI (용접 GUI) -│ └── ... -├── AuroraDevices (선택적) -│ ├── AuroraLaser (필수 - Laser 제어) -│ ├── AuroraOCT (필수 - OCT 스캔) -│ ├── AuroraPLC (필수 - PLC 통신) -│ ├── AuroraIO (필수 - IO 제어) -│ ├── AuroraCellTracker (필수 - 셀 추적) -│ ├── AuroraLBAD (?) -│ └── ... (기타 22개 중 필요 없는 것?) -├── AuroraComponents (필수) -├── AuroraVision (필요하나?) -└── NuGet 패키지 (Reactive, Json.NET, etc.) -``` - -**분석:** -- 각 AuroraDevices 프로젝트의 실제 사용 여부 -- 제거 가능한 의존성 -- 조건부 컴파일 가능성 (#if DEBUG 등) - -**산출물:** `_workspace/04a_dependency_analysis.csv` - -### 3단계: 빌드 구성별 최적화 - -#### Debug|x64 최적화 -- 기호 생성 필요 (유지) -- 최적화 비활성화 (유지) -- 증분 빌드 활용 - -#### Release|x64 최적화 -```xml - - true - embedded - true - true - -``` - -#### Simulation|x64 최적화 -```csharp -#if SIMULATION - // 하드웨어 통신 불필요 - 모의 구현 사용 - public class MockPLC : IPLC { ... } -#endif -``` - -#### UserDefineUnit|x64 최적화 -- 용도 파악 필요 (단위 테스트? 커스텀 하드웨어?) -- 필요한 기능만 포함 - -### 4단계: CI/CD 파이프라인 설계 - -**목표:** -- 자동 빌드 (commit, PR) -- 자동 테스트 (Simulation 구성) -- 자동 배포 (수동 승인) - -**추천 플랫폼:** -- GitHub Actions (GitHub 저장소 사용 중 가정) -- Azure Pipelines (Microsoft 클라우드) -- Jenkins (온프레미스) - -**파이프라인 구조:** -```yaml -# .github/workflows/ptop-build.yml -name: PTOP Build & Deploy - -on: - push: - branches: [main, develop] - paths: ['Machines/ILSOS_PrismaticRD_PTOP/**'] - pull_request: - branches: [main] - -jobs: - build: - runs-on: windows-latest - strategy: - matrix: - config: [Debug, Release, Simulation] - steps: - - uses: actions/checkout@v3 - - name: Setup .NET Framework - uses: microsoft/setup-msbuild@v1 - - name: Restore NuGet - run: nuget restore ILSOS_All.sln - - name: Build (${{ matrix.config }}) - run: msbuild ILSOS_All.sln /p:Configuration=${{ matrix.config }} /p:Platform=x64 - - name: Run Tests (Simulation only) - if: matrix.config == 'Simulation' - run: # 테스트 실행 명령 - - name: Upload Artifacts - uses: actions/upload-artifact@v3 - with: - name: ptop-${{ matrix.config }} - path: Machines/_out_prismatic_rd_ptop/x64-${{ matrix.config }}/ - - deploy: - needs: build - runs-on: windows-latest - if: github.ref == 'refs/heads/main' - environment: production # 수동 승인 필수 - steps: - - name: Download Release Artifact - - name: Create Release Package - run: # 패키징 스크립트 - - name: Deploy to Server - run: # 배포 스크립트 -``` - -### 5단계: 배포 패키징 - -**산출물:** -- 실행 가능 파일 (Aurora.exe) -- 필수 DLL (AuroraDevices, WeldingComponents, etc.) -- 설정 파일 (app.config) -- 리소스 파일 (이미지, 데이터) -- 배포 설명서 - -**패키징 형식:** -- ZIP 아카이브 (간단) -- NSIS 설치 프로그램 (사용자 친화적) -- Chocolatey 패키지 (자동 업데이트) - -## 통합 산출물 - -### 최종 보고서: `_workspace/04_ptop_build_optimization.md` - -```markdown -# PTOP 빌드 최적화 보고서 - -## 1. 현재 빌드 성능 - -| 구성 | 시간 | 병목 | 개선 가능성 | -|------|------|------|----------| -| Debug|x64 | 45s | ? | 개선 중심 | -| Release|x64 | 60s | ? | 최적화 중심 | -| Simulation|x64 | 50s | ? | 테스트 환경 | -| UserDefineUnit|x64 | 55s | ? | 커스텀 | - -## 2. 의존성 최적화 - -### 필수 의존성 -- AuroraLaser, AuroraOCT, AuroraPLC, etc. - -### 제거 가능 의존성 -- ... - -## 3. 빌드 구성별 최적화 전략 - -### Debug -- 현황: [상태] -- 개선안: [목표] -- 예상 효과: [시간 단축] - -### Release -- ... - -### Simulation -- ... - -## 4. CI/CD 파이프라인 - -[YAML 파일 포함] - -## 5. 배포 패키징 - -[패키징 스크립트] - -## 6. 예상 효과 - -- 빌드 시간: XX% 단축 -- 배포 시간: XX% 단축 -- 자동화: 수동 작업 제거 -``` - -## 입력 조건 - -사용자 요청 시: -- "PTOP 빌드 최적화" -- "빌드 시간 단축" -- "CI/CD 파이프라인 설계" -- "배포 자동화" -- "Release 빌드 성능" - -## 출력 결과 - -- 빌드 성능 분석 보고서 -- 의존성 맵핑 CSV -- CI/CD 파이프라인 (YAML/JSON) -- 빌드 최적화 설정 (PropertyGroup) -- 배포 패키징 스크립트 -- 최종 보고서 - -## 주의사항 - -1. **.NET Framework 4.8.1 호환성** — 최신 .NET 기능 사용 불가 -2. **Visual Studio 2022 기준** — MSBuild 경로 확인 -3. **Windows 플랫폼 전용** — x64 아키텍처 명시 -4. **빌드 머신 사양** — CI 환경의 OS/RAM 확인 -5. **라이선스 확인** — NuGet 패키지, 외부 도구의 라이선스 diff --git a/.ubisam_agent/skills/orchestrate-ptop-harness/SKILL.md b/.ubisam_agent/skills/orchestrate-ptop-harness/SKILL.md deleted file mode 100644 index 1f9ea95..0000000 --- a/.ubisam_agent/skills/orchestrate-ptop-harness/SKILL.md +++ /dev/null @@ -1,286 +0,0 @@ ---- -name: orchestrate-ptop-harness -description: ILSOS_PrismaticRD_PTOP 개발 팀의 오케스트레이터. 3명 팀원(PTOP Lead, PTOP Developer, Build/DevOps Engineer)의 작업을 조율하고 아키텍처 분석, 구현 분석, 빌드 최적화를 통합 진행. "PTOP 프로젝트 종합 분석", "PTOP 전체 점검", "PTOP 하네스 시작", "PTOP 팀 조율" 요청 시 사용. ---- - -# Orchestrate PTOP Harness Skill - -## 목표 - -ILSOS_PrismaticRD_PTOP의 **3계층 아키텍처**, **구현 상세**, **빌드 최적화**를 **병렬 분석**하여 팀원들이 조율하며 통합 보고서를 완성한다. - -## 실행 모드 - -**에이전트 팀** (팀 조율 활성화) - -``` -[오케스트레이터] - ├─ TeamCreate(team=[PTOP Lead, PTOP Developer, Build/DevOps Engineer]) - ├─ Phase 1: 초기 컨텍스트 확인 - ├─ Phase 2: 병렬 분석 작업 할당 (TaskCreate + 팀원 간 SendMessage) - ├─ Phase 3: 결과 수집 및 통합 - ├─ Phase 4: 최종 검증 - └─ Phase 5: 팀 해제 -``` - -## 워크플로우 - -### Phase 1: 초기 컨텍스트 확인 (5분) - -**수행 항목:** -1. `_workspace/` 디렉토리 존재 여부 확인 - - 존재 → 기존 분석 파일 로드, 부분 재실행 검토 - - 미존재 → 새 작업 시작 - -2. 기존 분석이 있으면: - - 이전 PTOP Lead의 보고서 검토 - - PTOP Developer의 발견사항 검토 - - Build Engineer의 개선안 검토 - - → 파일을 `_workspace_prev/`로 이동 후 신규 분석 진행 - -**산출:** -- Phase 1 진행 상황 (TaskCreate 할당) - -### Phase 2: 병렬 분석 작업 할당 (15~20분) - -**TaskCreate 3개 발행:** - -#### Task 2-1: PTOP Lead — 아키텍처 분석 -``` -Role: PTOP Lead -Task: analyze-ptop-architecture 스킬 실행 -Input: - - ILSOS_PrismaticRD_PTOP 소스 전체 - - CLAUDE.md 프로젝트 컨텍스트 -Output: - - _workspace/01a_equipdef_analysis.md - - _workspace/01b_sequences_analysis.md - - _workspace/01c_device_analysis.md - - _workspace/01d_rxnet_analysis.md - - _workspace/01e_device_integration.md - - _workspace/01_ptop_architecture.md (통합) -Deadline: 20분 -Status: in_progress -``` - -#### Task 2-2: PTOP Developer — 구현 분석 -``` -Role: PTOP Developer -Task: analyze-ptop-implementation 스킬 실행 -Input: - - PTOP Lead의 01_ptop_architecture.md (참고) - - SeqAutoRunPTOP.cs, Device/* 소스 -Output: - - _workspace/02_ptop_implementation.md (상태 머신, 타이밍, 에러 처리 포함) -Dependencies: Task 2-1의 아키텍처 정의 완료 후 진행 -Deadline: 20분 -Status: blocked (대기) -``` - -#### Task 2-3: Build/DevOps Engineer — 빌드 최적화 -``` -Role: Build/DevOps Engineer -Task: optimize-ptop-build 스킬 실행 -Input: - - ILSOS_All.sln 파일 - - 현재 빌드 환경 정보 -Output: - - _workspace/04a_dependency_analysis.csv - - _workspace/04_ptop_build_optimization.md (CI/CD 파이프라인 포함) -Status: in_progress (독립적) -Deadline: 15분 -``` - -**병렬 실행 전략:** -- Task 2-1과 2-3은 독립적 → 동시 진행 -- Task 2-2는 Task 2-1 결과 참고 필요 → 순차 - -**팀 통신:** -``` -[오케스트레이터 → PTOP Lead] - "아키텍처 분석 시작. 20분 안에 01_ptop_architecture.md 완성 부탁." - -[오케스트레이터 → PTOP Developer] - "PTOP Lead의 아키텍처 분석 대기 중. 시작 신호 받으면 구현 분석 시작할 것." - -[오케스트레이터 → Build/DevOps Engineer] - "빌드 최적화 분석 시작. 15분 안에 04_ptop_build_optimization.md 완성 부탁." -``` - -### Phase 3: 중간 체크포인트 (10분) - -**T+10분 타이밍:** -``` -[오케스트레이터] - - PTOP Lead의 01_ptop_architecture.md 완성 확인 - - Build/DevOps Engineer의 진행상황 확인 - - [PTOP Developer에게 GO신호 발행] - "PTOP Lead의 아키텍처 분석 완료. 이제 구현 분석 시작해주세요." -``` - -**SendMessage 패턴:** -``` -[오케스트레이터 → PTOP Lead, PTOP Developer] - "두 분석의 연계 포인트를 확인해주세요. - - 아키텍처에서 정의한 3계층이 구현에 제대로 반영되었나? - - 의도하지 않은 구조가 있나?" -``` - -### Phase 4: 결과 수집 (5분) - -**수행 항목:** -1. 3개 분석 결과 파일 모두 완성 확인 -2. 각 팀원의 발견사항 요약 요청 (SendMessage) - -``` -[오케스트레이터 → 각 팀원] - "분석 완료되셨나요? 가장 중요한 발견 3개를 나열해주세요." - -PTOP Lead의 응답: - 1. SeqAutoRunPTOP이 메인 시퀀스이고 260605에 추가됨 - 2. PLC, Laser, OCT, CellTracker 모두 필수 디바이스 - 3. Rx.NET 메시지 흐름이 복잡 - 개선 필요 - -PTOP Developer의 응답: - 1. 상태 머신이 명확하지 않은 부분 발견 (XXX) - 2. PLC 호출 순서가 타이밍 크리티컬 - 3. OCT 스캔 시간 최적화 기회 - -Build/DevOps Engineer의 응답: - 1. Release 빌드가 Debug보다 20% 느림 - 2. AuroraDevices 중 불필요한 프로젝트 5개 발견 - 3. CI/CD 파이프라인 설계 완료 -``` - -### Phase 5: 통합 보고서 생성 (10분) - -**오케스트레이터가 종합:** - -`_workspace/00_PTOP_HARNESS_SUMMARY.md` 생성 - -```markdown -# ILSOS_PrismaticRD_PTOP 하네스 분석 — 종합 보고서 - -**분석 일시:** [날짜] -**팀원:** PTOP Lead, PTOP Developer, Build/DevOps Engineer -**총 소요시간:** ~50분 - ---- - -## Executive Summary - -ILSOS_PrismaticRD_PTOP은 [간단 설명] - -### 주요 발견 - -#### 아키텍처 (PTOP Lead) -- 3계층 구조 검증 완료 -- 핵심 컴포넌트: [리스트] -- 개선 우선순위: [P0, P1, P2] - -#### 구현 (PTOP Developer) -- 상태 머신 분석 완료 -- 성능 병목: [리스트] -- 안정성 이슈: [리스트] - -#### 빌드 (Build/DevOps Engineer) -- 빌드 성능: [현황] -- 의존성 최적화: [개선안] -- CI/CD: [설계 완료] - ---- - -## 상세 분석 - -### 1. 아키텍처 -[01_ptop_architecture.md 요약] - -### 2. 구현 -[02_ptop_implementation.md 요약] - -### 3. 빌드 & DevOps -[04_ptop_build_optimization.md 요약] - ---- - -## 종합 권장사항 - -| 우선순위 | 항목 | 담당 | 예상 공수 | -|---------|------|------|---------| -| P0 | [긴급] | PTOP Developer | ? | -| P1 | [중요] | PTOP Lead | ? | -| P2 | [개선] | Build/DevOps Engineer | ? | - ---- - -## 다음 단계 - -1. 이 보고서 검토 (팀 + 사용자) -2. P0 항목 즉시 대응 -3. P1 항목 일정 수립 -4. P2 항목 백로그 등록 - ---- - -## 부록 - -- [분석 파일 목록] -- [팀 통신 기록] -- [시간 로그] -``` - -### Phase 6: 팀 정리 및 후속 계획 - -``` -[오케스트레이터] - ✓ 팀 해제 (TeamDelete) - ✓ 최종 보고서 제출 - → 사용자에게 결과 요약 제시 - -[사용자에게 제시] - "PTOP 하네스 분석 완료. 주요 발견: - 1. 아키텍처: 3계층 구조 검증 완료 (문서: 01_ptop_architecture.md) - 2. 구현: 상태 머신 분석, 성능 병목 식별 (문서: 02_ptop_implementation.md) - 3. 빌드: 최적화 기회 발견, CI/CD 설계 완료 (문서: 04_ptop_build_optimization.md) - - 다음 단계: 보고서 검토 → P0 항목 대응" -``` - -## 데이터 전달 프로토콜 - -| 전달 객체 | 방식 | 용도 | -|----------|------|------| -| 팀원 간 작업 결과 | 파일 (_workspace/) | 아키텍처 → 구현 분석 의존성 | -| 팀원 간 실시간 소통 | SendMessage | 질문, 상충 해결, 진행상황 | -| 최종 산출물 | 통합 보고서 + 세부 파일 | 사용자 제시 | - -## 에러 핸들링 - -| 상황 | 처리 방식 | -|------|---------| -| 팀원 분석 지연 | 진행상황 확인, 추가 시간 할당 | -| 팀원 간 의견 상충 | SendMessage로 토론, 양쪽 견해 모두 기록 | -| 코드 이해 불가 | 해당 부분을 "불명확" 표시하고 진행 | -| 분석 결과 불완전 | 세부 파일에 "TODO" 표시, 최종 보고서에 명시 | - -## 성공 기준 - -- [ ] 5개 세부 분석 문서 완성 (01a~01e, 02, 04a, 04) -- [ ] 3개 팀원 모두 할당된 작업 완료 -- [ ] 통합 보고서 (00_PTOP_HARNESS_SUMMARY.md) 생성 -- [ ] 주요 발견사항 3개 이상 도출 -- [ ] 권장사항(P0/P1/P2)이 명확히 기술됨 -- [ ] 모든 분석이 코드 레퍼런스와 함께 기술됨 -- [ ] 팀원 간 의견 상충 없이 완료되거나, 상충이 있으면 명시적으로 기록됨 - -## 후속 작업 - -이 하네스는 초기 분석이며, 이후: -- P0 항목 대응 후 재검토 -- P1 항목 진행 중 코드 리뷰 (별도 하네스) -- P2 항목 백로그 관리 - -**재실행 트리거:** -- 사용자가 "PTOP 재분석", "PTOP 상태 업데이트" 요청 시 -- 주요 코드 변경 후 영향도 분석 필요 시 diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 6ecf826..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,58 +0,0 @@ -# ILSOS 프로젝트 — Claude 초기 컨텍스트 - -## 목차 - -1. [프로젝트 문서](#1-프로젝트-문서) -2. [협업 규칙](#2-협업-규칙) -3. [하네스](#3-하네스) -4. [Aurora 프레임워크 레퍼런스](#4-aurora-프레임워크-레퍼런스) - ---- - -## 1. 프로젝트 문서 - -@./docs/architecture.md -> 프로젝트 개요, 솔루션 구조, PTOP 아키텍처, 디바이스, 빌드, 하네스 통합 문서 - ---- - -## 2. 협업 규칙 - -@./rules.md - ---- - -## 3. 하네스 - -에이전트 정의는 `.claude/agents/`, 스킬은 `.claude/skills/`에 둔다. 다른 경로에 두면 로딩되지 않는다. - -**트리거 규칙 — 요청을 아래로 라우팅한다. 단순 질문은 직접 응답 가능.** - -| 요청 | 스킬 | -|---|---| -| PTOP 아키텍처·구현·빌드 **분석** ("PTOP 전체 점검", "PTOP 재분석") | `orchestrate-ptop-harness` | -| Ubisam **산출물** 생성·재생산 ("산출물 만들어줘", "Ubisam 양식으로") | 입력에 따라 분기 → `docs/harness-ubisam.md` | -| PTOP **코드를 실제로 수정** | `code_Agent` (분석 하네스 아님. **사용자 전역 스킬** — 이 저장소에는 없다) | -| 화면 레이아웃 도식 이미지 | `ui_layout_image` | -| 작업일지 기록 | `doyeon_note` | - -산출물 요청에 **대상이 명시되지 않으면**(예: "산출물 업데이트해줘") 어떤 스킬도 바로 실행하지 말고 -소스코드인지·기존 문서인지·트리 생성인지를 먼저 되묻는다. -대상 없는 **"다시 실행"·"업데이트"·"보완"** 만으로는 어떤 하네스도 기동하지 않는다 — -무엇을 다시 실행할지 먼저 묻는다. - -@./docs/harness-ptop.md -> PTOP 분석 하네스(팀 구성, 트리거, 구성 요소, 변경 이력) -@./docs/harness-ubisam.md -> Ubisam 산출물 하네스(스킬 선택 기준, 팀 구성, 변경 이력) - ---- - -## 4. Aurora 프레임워크 레퍼런스 - -Aurora 2.0 개발 규칙·API·패턴을 토큰 최소로 찾기 위한 인덱스형 지식베이스. Aurora 관련 작업(디바이스·시퀀스·PLC·ViewModel·빌드) 시 아래 README의 라우팅 표를 먼저 본다. - -@./docs/Aurora에이전트레퍼런스모음/README.md -> Aurora 레퍼런스 인덱스(라우팅 허브) → 01_concepts / 02_patterns / 03_gotchas … -> ⚠ 이 폴더는 `.gitignore` 제외(로컬 전용)라 clone 직후에는 없다. 없으면 이 임포트는 조용히 비고, -> Aurora 질문은 `External/Aurora/Aurora2.0_Guide.pdf`와 소스 코드로 직접 확인해야 한다. diff --git a/README.md b/README.md deleted file mode 100644 index 705b691..0000000 --- a/README.md +++ /dev/null @@ -1,92 +0,0 @@ -# ILSOS - - - -## Getting started - -To make it easy for you to get started with GitLab, here's a list of recommended next steps. - -Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! - -## Add your files - -- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files -- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: - -``` -cd existing_repo -git remote add origin http://mod.lge.com/hub/sungkyun.cho/ilsos.git -git branch -M main -git push -uf origin main -``` - -## Integrate with your tools - -- [ ] [Set up project integrations](http://mod.lge.com/hub/sungkyun.cho/ilsos/-/settings/integrations) - -## Collaborate with your team - -- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) -- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) -- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) -- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) -- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) - -## Test and Deploy - -Use the built-in continuous integration in GitLab. - -- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) -- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) -- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) -- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) -- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) - -*** - -# Editing this README - -When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template. - -## Suggestions for a good README -Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. - -## Name -Choose a self-explaining name for your project. - -## Description -Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. - -## Badges -On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. - -## Visuals -Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. - -## Installation -Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. - -## Usage -Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. - -## Support -Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. - -## Roadmap -If you have ideas for releases in the future, it is a good idea to list them in the README. - -## Contributing -State if you are open to contributions and what your requirements are for accepting them. - -For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. - -You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. - -## Authors and acknowledgment -Show your appreciation to those who have contributed to the project. - -## License -For open source projects, say how it is licensed. - -## Project status -If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. diff --git a/docs/CODING_RULES.md b/docs/CODING_RULES.md deleted file mode 100644 index d22ab8d..0000000 --- a/docs/CODING_RULES.md +++ /dev/null @@ -1,115 +0,0 @@ -# 코딩 규칙 — ILSOS 프로젝트 - -## 1. 파일 인코딩 규칙 (필수) - -### 규칙: 모든 C# / XAML / 텍스트 파일은 UTF-8 with BOM + CRLF - -이 프로젝트의 모든 소스 파일은 **UTF-8 with BOM** 인코딩과 **CRLF** 줄바꿈을 사용한다. -Visual Studio 2022가 기본으로 생성하는 방식이며, 한글이 포함된 주석/문자열이 깨지지 않으려면 반드시 이를 지켜야 한다. - -``` -인코딩: UTF-8 with BOM (BOM = EF BB BF) -줄바꿈: CRLF (\r\n) -``` - -### Claude가 파일을 생성/수정할 때 지켜야 할 사항 - -#### 파일 신규 생성 시 -- `Write` 도구로 파일을 생성한 뒤, **반드시** 아래 Python 명령으로 BOM을 추가하고 CRLF로 변환한다. - -```bash -python3 -c " -import sys -path = r'생성한_파일_경로.cs' -with open(path, 'r', encoding='utf-8') as f: - content = f.read() -content = content.replace('\r\n', '\n').replace('\n', '\r\n') -with open(path, 'wb') as f: - f.write(b'\xef\xbb\xbf') # UTF-8 BOM - f.write(content.encode('utf-8')) -" -``` - -#### 기존 파일 수정 시 -- `Edit` 도구로 파일을 수정한 경우, BOM과 CRLF는 기존 파일에 유지된다. - 단, Edit 도구가 BOM을 제거하거나 LF로 변경한 경우에는 위 Python 명령으로 복구한다. - -#### 수정 후 인코딩 검증 -```bash -python3 -c " -with open(r'파일경로.cs', 'rb') as f: - raw = f.read(3) -print('BOM 존재:', raw == b'\xef\xbb\xbf') # True여야 함 -" - -file 파일경로.cs -# 출력에 'UTF-8 (with BOM)' 및 'CRLF' 포함되어야 함 -``` - ---- - -## 2. 한글 깨짐 방지 체크리스트 - -파일을 생성하거나 수정한 후 아래를 확인한다. - -- [ ] `file` 명령 출력에 `UTF-8 (with BOM)` 포함 -- [ ] `file` 명령 출력에 `CRLF` 포함 -- [ ] 파일 첫 3바이트가 `EF BB BF` (BOM) -- [ ] 한글 주석/문자열이 포함된 경우 Visual Studio에서 열어 깨짐 여부 확인 - ---- - -## 3. 네이밍 컨벤션 - -### 클래스/메서드 -- **PascalCase**: `SequenceManager`, `EquipmentSetup`, `SeqAutoRunPTOP` - -### 필드/변수 -- **private 필드**: `_camelCase` (언더스코어 접두사) - 예) `_acs`, `_plc`, `_ajin` -- **지역 변수**: `camelCase` - -### 파일명 -- 클래스명과 동일하게 유지 -- Stage 구분: `StageA` / `StageB` 접미사 - ---- - -## 4. 시퀀스 작성 규칙 - -### ID 등록 -- 새 시퀀스/디바이스/레시피/뷰 추가 시 **반드시** `EquipDef.cs`의 해당 ID 클래스에 상수를 먼저 등록한다. - ---- - -## 5. 디바이스 추가 규칙 - -1. `EquipDef.cs` → `DeviceIds` 상수 추가 -2. `EquipmentSetup.cs` → 디바이스 인스턴스 생성 및 이벤트 구독 -3. `EquipmentSetup.cs` → `BuildMainStatusView()`에 상태 항목 추가 -4. 필요 시 `AuroraDevices/` 하위에 새 디바이스 프로젝트 생성 - ---- - -## 6. 주석 작성 - -- 한글 주석 사용 권장 (팀 내부 프로젝트) -- 주석에 한글이 포함되는 파일은 인코딩 규칙(섹션 1) 필수 적용 -- 복잡한 시퀀스 흐름은 단계별 번호 주석 사용: - ```csharp - // 1. 로드 완료 대기 - // 2. 높이 측정 - // 3. 용접 위치 이동 - // 4. 용접 실행 - ``` - ---- - -## 7. 빠른 참조 - -| 작업 | 규칙 | -|------|------| -| 새 C# 파일 생성 | UTF-8 BOM + CRLF 적용 필수 | -| 새 시퀀스 추가 | EquipDef.cs ID 등록 → 파일 생성 | -| 새 디바이스 추가 | EquipDef.cs → EquipmentSetup.cs → BuildMainStatusView | -| 한글 포함 수정 | 수정 후 BOM/CRLF 검증 | diff --git a/docs/GIT_RULES.md b/docs/GIT_RULES.md deleted file mode 100644 index de70a37..0000000 --- a/docs/GIT_RULES.md +++ /dev/null @@ -1,70 +0,0 @@ -# Git 커밋 규칙 — ILSOS 프로젝트 - -## 1. 빌드 산출물(bin) 무시 규칙 - -`.gitignore`는 전역적으로 빌드 산출물을 커밋에서 제외한다. - -``` -obj/ -bin/ -``` - -- `bin/` 은 폴더명이 `bin` 인 모든 디렉터리를 무시한다. -- 그 외 프로젝트별 산출물 경로(`_out_*`, `_intermediate/` 등)도 무시 대상이다. - ---- - -## 2. 예외: External/Aurora/bin 은 전체 커밋 - -`External/Aurora/bin` 는 외부 Aurora 런타임 산출물로, **전체를 git에 커밋**한다. -전역 `bin/` 무시 규칙은 그대로 두고, negation(`!`)으로 해당 폴더만 다시 포함한다. - -### `.gitignore` 설정 - -``` -bin/ - -# 예외: External/Aurora 폴더의 bin은 전체 커밋 -!/External/Aurora/bin/ -!/External/Aurora/bin/** -``` - -- `!/External/Aurora/bin/` — 무시된 `bin` 디렉터리 자체를 다시 포함한다. -- `!/External/Aurora/bin/**` — 그 하위의 모든 파일/폴더를 다시 포함한다. -- 두 줄 모두 필요하다. 디렉터리만 negation 하면 git이 하위로 내려가지 않아 파일이 포함되지 않는다. - -### 검증 방법 - -```bash -# bin 폴더가 더 이상 무시되지 않는지 확인 (negation 규칙 라인이 출력되어야 함) -git check-ignore -v External/Aurora/bin/ - -# 스테이징 -git add External/Aurora/bin -``` - ---- - -## 3. `.gitignore` 자체 커밋 - -`.gitignore` 는 다음 라인으로 **자기 자신을 무시**한다. - -``` -/.gitignore -``` - -따라서 `.gitignore` 변경분을 커밋하려면 `-f` 로 강제 추가해야 한다. - -```bash -git add -f .gitignore -``` - ---- - -## 4. 빠른 참조 - -| 대상 | 처리 | -|------|------| -| 일반 `bin/` 산출물 | 무시 (커밋 안 함) | -| `External/Aurora/bin` | 전체 커밋 (negation 예외) | -| `.gitignore` 수정 | `git add -f .gitignore` | diff --git a/docs/PtoP 유니셀 용접기 PLC 인터페이스/유니셀 PtoP 단동기 Laser Interface_260622_변경.xlsx b/docs/PtoP 유니셀 용접기 PLC 인터페이스/유니셀 PtoP 단동기 Laser Interface_260622_변경.xlsx deleted file mode 100644 index 8f60056..0000000 Binary files a/docs/PtoP 유니셀 용접기 PLC 인터페이스/유니셀 PtoP 단동기 Laser Interface_260622_변경.xlsx and /dev/null differ diff --git a/docs/PtoP 유니셀 용접기 PLC 인터페이스/유니셀 PtoP 단동기 Laser Interface_260730_레시피NUM변경.xlsx b/docs/PtoP 유니셀 용접기 PLC 인터페이스/유니셀 PtoP 단동기 Laser Interface_260730_레시피NUM변경.xlsx deleted file mode 100644 index 2747d96..0000000 Binary files a/docs/PtoP 유니셀 용접기 PLC 인터페이스/유니셀 PtoP 단동기 Laser Interface_260730_레시피NUM변경.xlsx and /dev/null differ diff --git a/docs/architecture.md b/docs/architecture.md deleted file mode 100644 index 2be697a..0000000 --- a/docs/architecture.md +++ /dev/null @@ -1,200 +0,0 @@ -# ILSOS 프로젝트 아키텍처 - -> CLAUDE.md의 "프로젝트 문서" 섹션에서 import하던 개별 문서들을 통합한 아키텍처 문서입니다. -> 세부 내용은 각 원본 문서를 참고하세요. - -## 목차 - -1. [프로젝트 개요](#1-프로젝트-개요) -2. [솔루션 구조](#2-솔루션-구조) -3. [ILSOS_PrismaticRD_PTOP 핵심 구조](#3-ilsos_prismaticrd_ptop-핵심-구조) -4. [AuroraDevices 모듈](#4-auroradevices-모듈) -5. [빌드 출력 경로](#5-빌드-출력-경로) -6. [PTOP 분석 하네스](#6-ptop-분석-하네스) -7. [Git 커밋 규칙](#7-git-커밋-규칙) -8. [용어 정리](#8-용어-정리-unicell-ptop-welder) - ---- - -## 1. 프로젝트 개요 - -> 원본: [`project-overview.md`](./project-overview.md) - -### ILSOS - OC5 PilotLine RectangleTypeWelder - -**목표:** 각형 배터리 용접 자동화 시스템 - -**플랫폼 및 기술:** -- OS: Windows 10 / Windows 11 -- 프레임워크: .NET Framework 4.8.1 -- IDE: Visual Studio 2022 -- UI 프레임워크: WPF (Aurora 프레임워크 기반) -- 솔루션 파일: `ILSOS_All.sln` - -**빌드 구성:** -- Debug | x64 -- Release | x64 -- Simulation | x64 · UserDefineUnit | x64 — **PTOP 기준 `Release|x64`로 매핑**(`ILSOS_All.sln:413-416`). - 별도 바이너리가 아니다 (§5 참조) - -**머신 모듈:** -- **ILSOS_PrismaticRD_PTOP**: 현재 유일한 활성 머신 모듈 (주요 개발 대상) - - 과거 Scanner/Gun/CleanLaser 모듈은 제거됨 (솔루션에 csproj 없음) - -**주의사항:** -- WeldingComponents·External/Aurora 관련 코드 수정 시 반드시 사전 승인 필요 -- 모든 파일 수정 시 `docs/CODING_RULES.md` 확인 필수 -- 한글 포함 파일 작성/수정 시 UTF-8 인코딩 준수 - ---- - -## 2. 솔루션 구조 - -> 원본: [`solution-structure.md`](./solution-structure.md) - -### ILSOS_All.sln 구성 - -``` -ILSOS_All.sln -├── Machines/ -│ └── ILSOS_PrismaticRD_PTOP/ ← 현재 유일한 활성 머신 모듈 (3계층 아키텍처) -├── AuroraDevices/ ← 하드웨어 디바이스 드라이버 (sln 등록 20개 / 디스크 22개) -├── AuroraComponents/ ← WPF UI 공통 컴포넌트 -├── AuroraVision/ ← 비전 시스템 (MIL 기반) -├── WeldingComponents/ ← 용접 공통 기능 -│ ├── WeldingCommon -│ └── LASAGUI -└── External/ ← Aurora 프레임워크 바이너리 -``` - -### 주요 특징 - -- **모듈화:** 머신 모듈은 독립적인 디바이스 제어 및 시퀀스 구현 -- **공유 레이어:** AuroraDevices, AuroraComponents 등으로 코드 재사용 -- **표준 규칙:** WeldingComponents·External/Aurora는 수정 시 승인 필수 - ---- - -## 3. ILSOS_PrismaticRD_PTOP 핵심 구조 - -> 원본: [`ptop-architecture.md`](./ptop-architecture.md) - -### 폴더 구조 및 주요 컴포넌트 - -``` -ILSOS_PrismaticRD_PTOP/ -├── EquipDef.cs ← ID 상수 (DeviceIds / SequenceIds / StreamMessageNames) -├── EquipmentSetup.cs ← 디바이스·시퀀스 등록, 이벤트 구독 -├── Alarm/ ← AlarmCode_PTOP, AlarmManager_PTOP -├── Device/{IO,PLC}/ ← PAIX_PTOP(IO), PLCControllerPTOP(PLC) -├── Models/ ← EquipmentSpecificModel_PTOP -├── Recipes/ ← RMSHandlerForPTOP -├── Sequences/ ← SeqAutoRunPTOP(메인) 외 + Manual/, Monitoring/ -├── Settings/ ← SettingUploadDataListForPTOP -└── Views/{Main,Model}/ ← WPF View/ViewModel -``` - -### 주요 ID 정의 (EquipDef.cs) - -| 클래스 | 멤버 (발췌) | -|---------|------| -| **DeviceIds** : CommonDeviceIds | `MassFlowMeter` (그 외 base 상속) | -| **SequenceIds** : CommonSequenceIds | `SeqAutoRunPTOP`, `SeqAutoRunTDC`, `SeqAutoRunComponentWeld`, `SeqAlarmMonitor`, `SeqStatusMonitor`, `SeqTestRun`, `SeqStreamTest`, `SeqEventQTest` | -| **StreamMessageNames** | `MessageNameString/Double/Int/JSON/LBAD` | - -> `MotorIds`/`RecipeIds` 클래스는 없음 (base `Common*`·레시피 매니저에서 관리). 상세 → [`ptop-architecture.md`](./ptop-architecture.md) - -### 아키텍처 패턴 (3계층) - -``` -WPF UI Layer (Views/ + ViewModels) - ↓ -Machine Logic Layer (EquipmentSetup + Sequences) - ↓ -Device Abstraction (AuroraDevices — 디바이스별 독립 모듈) - ↓ -Hardware Layer (ACS.SPiiPlusNET, Melsec, Serial/USB) -``` - -**기술 스택:** System.Reactive(Rx) · AuroraEnv DI · 메시지 큐(String/Double/Int/JSON/LBAD) - ---- - -## 4. AuroraDevices 모듈 - -> 원본: [`aurora-devices.md`](./aurora-devices.md) - -AuroraDevices는 하드웨어 디바이스 제어를 담당하는 22개 프로젝트 모음입니다. - -| 프로젝트 | 역할 | 비고 | -|---------|------|------| -| AuroraDeviceCommon | 디바이스 공통 기본 클래스 | 모든 디바이스 상속 | -| AuroraACS | ACS SPiiPlus 모션 컨트롤러 | X/Y축 모션 제어 | -| AuroraMotionBoard | Ajin 모션 보드 | Z축 모션 제어 | -| AuroraLaser | 레이저 제어 (Gun 타입) | 고정 레이저 | -| AuroraLaserScanner | 레이저 스캐너 제어 | 동적 스캐닝 | -| AuroraPLC | Mitsubishi Melsec PLC 통신 | 외부 신호 제어 | -| AuroraIO | 디지털 I/O | 입출력 신호 | -| AuroraHeightSensor | Keyence 높이 센서 | 높이 측정 | -| AuroraCellTracker | 팰릿/셀 추적 시스템 | 셀 인식 및 위치 추적 | -| AuroraChiller | 냉각 장치 | 온도 제어 | -| AuroraOCT | Trumpf OCT 스캐너 | 옵티컬 측정 | - -**설계 원칙:** -- 각 디바이스는 독립적인 제어 로직 구현 -- 통합 제어는 머신 모듈의 EquipmentSetup에서 담당 -- 의존성 주입(DI) 패턴으로 느슨한 결합 유지 - ---- - -## 5. 빌드 출력 경로 - -> 원본: [`build-output.md`](./build-output.md) - -### 머신별 빌드 디렉토리 - -| 머신 모듈 | 출력 경로 | 상태 | -|---------|---------|------| -| ILSOS_PrismaticRD_PTOP | `Machines/_out_prismatic_rd_ptop/` | 활성 | - -### 빌드 구성별 출력 - -출력은 `구성-플랫폼` 하위 폴더로 분리 (csproj `OutputPath` 기준). -- `Machines/_out_prismatic_rd_ptop/x64-Debug/` ← Debug|x64 -- `Machines/_out_prismatic_rd_ptop/x64-Release/` ← Release|x64 (Simulation·UserDefineUnit도 Release 매핑) - -### 주의사항 - -- 빌드 출력 디렉토리는 `.gitignore`에 포함 -- 빌드 전 이전 출력물이 있으면 자동 정리 -- 각 머신 모듈은 독립적으로 빌드 가능 - ---- - -## 6. PTOP 분석 하네스 - -> 원본: [`harness-ptop.md`](./harness-ptop.md) - -ILSOS_PrismaticRD_PTOP의 아키텍처·구현·빌드를 종합 분석하는 에이전트 하네스. - -- **팀:** `ptop-lead` / `ptop-developer` / `build-devops-engineer` -- **트리거:** "PTOP 전체 분석", "PTOP 빌드 최적화" 등 → `orchestrate-ptop-harness` 스킬 -- **구성:** `.claude/agents/`(PTOP 팀 3개 / 저장소 전체 6개), `.claude/skills/`(PTOP 하네스 4개: analyze-ptop-architecture·-implementation, optimize-ptop-build, orchestrate-ptop-harness) - -> 2026-08-03에 `.ubisam_agent/` → `.claude/`로 이전. Claude Code는 `.claude/`만 로딩한다. - -Ubisam 산출물 하네스는 [`harness-ubisam.md`](./harness-ubisam.md) 참고. - -> 세부 트리거·구성 요소·변경 이력은 원본 문서 참고. - ---- - -## 7. Git 커밋 규칙 - -@./GIT_RULES.md - ---- - -## 8. 용어 정리 (UNICELL PTOP WELDER) - -@./용어정리.md diff --git a/docs/aurora-devices.md b/docs/aurora-devices.md deleted file mode 100644 index 17a4a81..0000000 --- a/docs/aurora-devices.md +++ /dev/null @@ -1,22 +0,0 @@ -# AuroraDevices 모듈 목록 - -AuroraDevices는 하드웨어 디바이스 제어를 담당하는 22개 프로젝트 모음입니다. - -| 프로젝트 | 역할 | 비고 | -|---------|------|------| -| AuroraDeviceCommon | 디바이스 공통 기본 클래스 | 모든 디바이스 상속 | -| AuroraACS | ACS SPiiPlus 모션 컨트롤러 | X/Y축 모션 제어 | -| AuroraMotionBoard | Ajin 모션 보드 | Z축 모션 제어 | -| AuroraLaser | 레이저 제어 (Gun 타입) | 고정 레이저 | -| AuroraLaserScanner | 레이저 스캐너 제어 | 동적 스캐닝 | -| AuroraPLC | Mitsubishi Melsec PLC 통신 | 외부 신호 제어 | -| AuroraIO | 디지털 I/O | 입출력 신호 | -| AuroraHeightSensor | Keyence 높이 센서 | 높이 측정 | -| AuroraCellTracker | 팰릿/셀 추적 시스템 | 셀 인식 및 위치 추적 | -| AuroraChiller | 냉각 장치 | 온도 제어 | -| AuroraOCT | Trumpf OCT 스캐너 | 옵티컬 측정 | - -**설계 원칙:** -- 각 디바이스는 독립적인 제어 로직 구현 -- 통합 제어는 머신 모듈의 EquipmentSetup에서 담당 -- 의존성 주입(DI) 패턴으로 느슨한 결합 유지 diff --git a/docs/build-output.md b/docs/build-output.md deleted file mode 100644 index e9f27f5..0000000 --- a/docs/build-output.md +++ /dev/null @@ -1,21 +0,0 @@ -# 빌드 출력 경로 - -## 머신별 빌드 디렉토리 - -| 머신 모듈 | 출력 경로 | 상태 | -|---------|---------|------| -| ILSOS_PrismaticRD_PTOP | `Machines/_out_prismatic_rd_ptop/` | 활성 | - -> 과거 Scanner/Gun/CleanLaser 출력 디렉토리는 해당 모듈 제거로 더 이상 생성되지 않음. - -## 빌드 구성별 출력 - -출력 폴더는 `구성-플랫폼` 형식의 하위 디렉토리로 분리된다 (csproj `OutputPath` 기준). - -- `Machines/_out_prismatic_rd_ptop/x64-Debug/` ← Debug|x64 -- `Machines/_out_prismatic_rd_ptop/x64-Release/` ← Release|x64 (Simulation·UserDefineUnit도 Release로 매핑) - -## 주의사항 - -- 빌드 출력 디렉토리는 `.gitignore`에 포함 -- **솔루션(`ILSOS_All.sln`) 기준으로 빌드**해야 post-build xcopy의 `$(SolutionDir)`가 정의됨 (단독 csproj 빌드 시 `*Undefined*` 경로로 실패) diff --git a/docs/harness-ptop-changelog.md b/docs/harness-ptop-changelog.md deleted file mode 100644 index 65c3b4c..0000000 --- a/docs/harness-ptop-changelog.md +++ /dev/null @@ -1,112 +0,0 @@ -# 하네스 변경 이력 — PTOP 분석 팀 - -> `docs/harness-ptop.md` 에서 분리했다 (`rules.md` #4 — 200줄 상한). -> 하네스를 고치면 **여기에 행을 추가**한다. 본문에는 표를 되돌리지 않는다. - -| 날짜 | 변경 내용 | 대상 | 사유 | -|------|----------|------|------| -| 2026-06-16 | 초기 구성: PTOP 분석 팀 구축 | agents/, skills/ | ILSOS_PrismaticRD_PTOP이 핵심 활성 모듈, 종합 분석 필요 | -| 2026-08-03 | `.ubisam_agent/` → `.claude/`로 경로 이전, `.gitignore`에 `!.claude/agents/` 예외 추가 | agents 3개, skills 4개 | Claude Code가 `.claude/`만 로딩 — 하네스 전체가 호출 불가 상태였음 | -| 2026-08-03 | `TeamCreate`/`TeamDelete` 의존 제거 → `Agent`+`SendMessage`로 교체 | orchestrate-ptop-harness, agents 3개 | 해당 도구가 이 환경에 존재하지 않아 오케스트레이터 실행 불가 | -| 2026-08-03 | 진행·재시도 원장을 `_progress.md` **파일**로 고정 (태스크 도구는 보조로 강등) | 스킬 2·에이전트 6·참조 3·하네스 문서 2 | `TaskCreate`/`TaskUpdate`가 **서브에이전트 컨텍스트에는 없어** 재시도 카운트가 매번 0으로 리셋 → "최대 2회" 상한이 무력화 | -| 2026-08-03 | 날조된 예시 분석 결과 삭제, "미측정" 표기 원칙 추가 | orchestrate-ptop-harness, build-devops-engineer | 예시 수치("Release가 20% 느림" 등)를 에이전트가 실측으로 오인해 복사할 위험 | -| 2026-08-03 | 산출 파일명을 에이전트 정의와 일치시킴(01~06), 팀원 이름 실제 에이전트명으로 정정 | orchestrate-ptop-harness, ptop-lead | 오케스트레이터↔에이전트 간 참조 불일치(dead link) | -| 2026-08-03 | `model: opus`·재호출 지침·분석 전용 명시 추가 | agents 3개 | 후속 실행 시 이전 산출물 재사용 규칙 부재 | -| 2026-08-03 | 보고서 템플릿·CI/CD YAML을 `references/`로 분리 (200줄 상한 준수) | analyze-ptop-architecture/-implementation, optimize-ptop-build | `rules.md` #4 위반 (248·210·209줄) | -| 2026-08-03 | 템플릿의 날조 수치(빌드 45s/60s, T+50ms, PLC `M10` 등)를 플레이스홀더로 교체 | 위 3개 스킬 references/ | 에이전트가 예시값을 실측으로 오인해 복사할 위험 | -| 2026-08-03 | 죽은 소스 경로 정정 + 동명 심볼 함정 명시 | analyze-ptop-architecture, ptop-lead, ptop-developer | 2026-06-18 리네임(`SeqAutoRunPrismaticScanner`→`SeqAutoRunPrismatic`, `PAIX_PrismaticScanner`→`PAIX_PTOP`) 미반영. `PLCContoller.Config.cs` 오탈자·공유 클래스 동명 문제도 병기 | -| 2026-08-03 | 에이전트 가용성 가드 + lead 2회 실패 폴백 + stale 표기 의무 추가 | orchestrate-ptop-harness | 에이전트 미등록 시 Phase 2에서 즉사, "지연"과 "실패"가 구분 안 됨, 부분 재실행 시 새 01+낡은 02가 무표기로 섞임 | -| 2026-08-03 | 산출 .md 200줄 상한 지시 추가 | agents 3개 | 하네스 자신은 준수하나 산출물에 대한 강제가 없었음 | -| 2026-08-03 | `.gitignore`에 `_workspace/`·`_workspace_prev/` 추가 | .gitignore | 하네스 중간 산출물이 레포 루트를 오염 | -| 2026-08-03 | `CLAUDE.md`의 `@import X` → `@X` 문법 정정 | CLAUDE.md, docs/architecture.md | `@import`는 Claude Code 문법이 아니라 조용히 실패 — `rules.md` 등 규약 문서 5건이 세션에 로딩되지 않고 있었음 | -| 2026-08-03 | `set PYTHONUTF8=1 &&` → `PYTHONUTF8=1` (bash 호환) | 스킬·에이전트·스크립트 9건 | bash에서 `set VAR=1`은 환경변수를 만들지 않아 stdout이 cp949로 깨짐 (`rules.md` #3 위반) | -| 2026-08-03 | 죽은 심볼·경로 정정: `Views/Recipe\|Manual\|Monitoring`(부재), `PAGE_VERIFY_DELAY_MS`·`WELD_START_DELAY_MS`(부재), `ThetaTolerance`→`HeadThetaTolerance` | ptop-deliverables/references/source-map.md | 진실원 인덱스가 없는 파일·상수를 지목 | -| 2026-08-03 | `ILSOS_PrismaticScanner 네임스페이스 사용` 주장 삭제 | ptop-lead, analyze-ptop-architecture | 실제 PTOP 네임스페이스는 `ILSOS_PrismaticRD_PTOP.*` (전수 확인, 옛 이름 0건) | -| 2026-08-03 | 승인 게이트·실패 판정 기준·Phase 3 완료 판정·이중 디스패치 해소 | orchestrate-ptop-harness, ptop-lead, ubisam-deliverables | `rules.md` #2 미준수, "지연"과 "실패"를 구분할 관측 기준 부재, lead와 오케스트레이터가 둘 다 developer를 기동 | -| 2026-08-03 | PTOP 하위 스킬 3개에 역방향 구분절 추가 | analyze-ptop-*, optimize-ptop-build | 종합 요청이 단일 영역 스킬로 새는 경로 | -| 2026-08-03 | msbuild 탐색 폴백 + 미측정 확정 절차 | optimize-ptop-build | `msbuild`가 PATH에 없어 1단계에서 막힘 | -| 2026-08-03 | .NET Core 전용 속성·`#if SIMULATION`·`MockPLC` 예시 삭제 | optimize-ptop-build, cicd 템플릿 | 이 프로젝트는 .NET Framework 4.8.1 legacy csproj. `Simulation\|x64`는 sln에서 `Release\|x64`로 매핑되며 `#if SIMULATION` 0건 — 존재하지 않는 빌드를 대상으로 삼게 됨 | -| 2026-08-03 | `MotorIds`→`SettingIds`, `PLC_HEAVY_ALARM_STATUS` 출처→`SeqAlarmMonitor.cs:199`, 진행률 스냅샷 제거 | analyze-ptop-architecture, source-map | 없는 클래스 지목·처리 위치 오지목·근거 없는 수치 | -| 2026-08-03 | 산출 경로 절대경로 변환 + `_workspace/` 사전 생성 지시 | orchestrate-ptop-harness | 서브에이전트 셸 cwd가 호출마다 초기화돼 상대경로 산출물이 유실되면 완료 판정이 오판 | -| 2026-08-03 | PTOP 3인에 담당 스킬 역참조 1줄씩 추가 | agents 3개 | 단독 호출 시 스킬이 적용되지 않음 (ubisam 3인은 이미 보유) | -| 2026-08-03 | qa 양식 미정의 폴백 수신 규칙 추가(#6만 미검증, #2는 정상 검증) | ubisam-qa, ubisam-producer | producer가 qa 동작을 일방 규정하고 있었고 enum 적용 여부와 자기모순 | -| 2026-08-03 | Ubisam 하네스에 실패 판정 기준·stale 표기 이식, Phase off-by-one 수정 | ubisam-deliverable-rebuild | Phase 0 후 "Phase 2 시작"으로 적혀 analyst를 건너뛰면 매핑표 없이 producer가 즉사 | -| 2026-08-03 | 네임스페이스 단정 정정 — 프로젝트 내 예외 3파일 병기 | ptop-lead, analyze-ptop-architecture | `SeqTestRun.cs:35`=TDC, `SeqAlarmMonitor.cs:22`·`SeqStatusMonitor.cs:11`=WeldingCommon. 앞선 "전부 `ILSOS_PrismaticRD_PTOP.*`" 주장이 거짓이었고, 그대로 grep하면 하네스가 인용하는 `SeqAlarmMonitor.cs:199`가 누락 | -| 2026-08-03 | 4구성 → **2구성**으로 통일 (description·측정표·보고서 템플릿) | optimize-ptop-build ×2, build-devops-engineer, architecture.md | `Simulation`·`UserDefineUnit`은 `ILSOS_All.sln:413-416`에서 Release 매핑 — 존재하지 않는 빌드를 측정 대상으로 요구하고 있었음 | -| 2026-08-03 | Phase 3 절대경로 전달·Phase 4 완료 알림 대기·재시도 카운트 기록 규칙 | orchestrate-ptop-harness, ubisam-deliverable-rebuild | Phase 2에만 있던 규칙이 전파되지 않아 `02`·`03` 유실 위험, "2회"를 세는 주체 부재 | -| 2026-08-03 | 스킬 폴더 잔재 정리(`생성파일/*.pptx`, `__pycache__`) + `.gitignore` 보강 | .claude/skills, .gitignore | 스킬이 스스로 금지한 "출력이 스킬 폴더로 새는 것"의 흔적 | -| 2026-08-03 | **`rules.md` #15·#16 바인딩** — 에이전트 6 + 스킬 6에 `[추론]` 표기 의무 삽입, `ubisam-qa` 검증항목 11 신설 | agents 6, skills 6 | 신규 조항이 하네스 어디에도 인용되지 않아 **미시행 상태**였다(문자열 `추론` 0건). 검증 주체가 없는 규칙은 문서에만 남는다 | -| 2026-08-03 | 표기 축 판정표 신설 (`파일:라인` / `미측정`계 / `[추론]` / `(제안)`계) | rules.md, 두 하네스 문서 | `[추론]`과 기존 미확정 표기 5종의 관계가 미정의라 대체·이중표기 위험 | -| 2026-08-03 | `rules.md` #5의 `@import` → `@경로` 정정, #15·#16을 `## 검증·표기` 절로 분리 | rules.md | 규칙서가 **폐기된 문법을 지시**하고 있었다(이미 정정한 결함의 발원지). 신규 조항이 제목 없이 붙어 파일 번호가 1,2,3,15,16,4,5로 흐트러짐 | -| 2026-08-03 | 규칙 ↔ 바인딩 역인덱스 표 + `grep` 자가 점검 명령 추가 | docs/harness-ptop.md | 조항 추가 시 바인딩 누락이 3라운드 연속 지적 — 재발 방지 | -| 2026-08-03 | `ptop-lead` 성공 기준의 "교차 확인 질문" 체크박스를 오케스트레이터 경유 시로 조건부화 | ptop-lead.md | 질문 정의·기록처가 모두 오케스트레이터 소유라 **단독 기동 시 충족 불가능**한 체크박스였음 | -| 2026-08-03 | `141528_…md` 경로를 전체 경로로 명기 | ptop-deliverables/references/source-map.md | 앞 문장의 `06/17/`과 병렬로 읽히나 실제는 `06/20/` — 06/17에는 없는 파일 | -| 2026-08-03 | **`[추론]` 검색 시 `\[추론\]` 이스케이프 의무** 명시 | ubisam-qa(검증항목11·작업원칙), ubisam-deliverables, rules.md | 대괄호가 정규식 문자클래스라 `[추론]`은 `추`·`론` 한 글자에도 매치 → **과다 매치**. 경로 케이스(0건)와 달리 결과가 많아 "0건이면 의심" 가드에 안 걸린다(실측 확인) | -| 2026-08-03 | qa 성공 기준 "10개" → "**11개**" | ubisam-qa.md | 직전 패스에서 검증항목 11을 신설하고 최종 게이트를 안 고쳐, 신규 항목을 건너뛰어도 통과되는 상태였음 (**자체 유발 회귀**) | -| 2026-08-03 | 실행 모드 판별을 `_workspace/` 폴더 존재 → **산출물 `01`~`06` 존재**로 변경 | orchestrate-ptop-harness | 채점·로그 파일만 있어도 "부분 재실행"으로 오판정 | -| 2026-08-03 | 표기 축에 `미확인` 편입, `(추정)` → `[추론]` 통일 | rules.md, harness-ubisam, 00-harness.md | 판정표가 실사용 표기 2종을 누락 — 같은 축에 다른 토큰이 공존 | -| 2026-08-03 | `analyze-ptop-architecture` 단독 기동 시 stale 표기 의무 명시 | analyze-ptop-architecture | "아키텍처만 다시"가 두 스킬에 동시 귀속되는데 단독 경로엔 표기 주체가 없었음 | -| 2026-08-03 | `ubisam-deliverables` 자동 채움 단계에 `[추론]` 바인딩 | ubisam-deliverables/SKILL.md | 게이트 없이 값을 생성하는 유일 경로가 미바인딩으로 남아 있었음 | -| 2026-08-03 | `rules.md` 절 순서 정정(`## 규칙 관리` → `## 검증·표기`), 역인덱스 `#11~13` 스킬 수 6→8 | rules.md, harness-ptop.md | 조항 15·16이 14보다 앞서 배치돼 자기 지침과 상충. 역인덱스 수치 오기 | -| 2026-08-03 | **역인덱스에서 인용 건수 열 삭제** — "어디에 있어야 하는가"만 남기고 개수는 명령이 답하게 | docs/harness-ptop.md | **세 라운드 연속 자체 유발 회귀.** 바인딩을 늘릴 때마다 표의 숫자가 거짓이 됐다(17·17로 적고 실제 19·19). 숫자를 문서에 박는 구조 자체가 원인이라 열을 없앴다 | -| 2026-08-03 | `source-map.md` 무효 심볼 3행 정정 — `Register*Device`·`MenuId`·`ViewType`·`AuthLevel`·`AddNode`·`AddTransition` | ptop-deliverables/references/source-map.md | 전부 **소스 0건**. 실제는 `registry.Register`(활성 3) · `AddSubMenu(CommonViewIds.*, UC)`(26, 권한 인자 없음) · `AddAction`(17)/`AddDecision`(4)/`AddSubsequence`(3). 하네스가 금지한 "창작"을 스스로 유발하는 경로였음 | -| 2026-08-03 | **"0건" 가드에 `.gitignore` 원인 추가** | ubisam-qa.md, harness-ptop.md | 기존 가드는 대괄호만 원인으로 지목. 그런데 `rg` 는 `.gitignore` 를 존중하고 **검증 대상이 전부 무시 대상**(`docs/[Ubisam산출물]/`·`_workspace/`)이라 자기 산출물 검색이 0건이 된다(실측: 루트 glob 0 vs 실제 5) | -| 2026-08-03 | `SendMessage` 회신 대상 `to: "main"` 명시 | 에이전트 6 | 6개 모두 "오케스트레이터에 보고한다"고 쓰면서 수신자 표기가 **전 저장소 0건**. 이름으로 보내면 메인 대화에 닿지 않는다 | -| 2026-08-03 | 부분 상태(`01`만 있음) 분기 신설 + "전체 분석"을 이동 근거에서 제외 | orchestrate-ptop-harness, ubisam-deliverable-rebuild, test-scenarios.md | `01`만 있는 상태에 분기가 없고, "전체 분석"이 최초 실행과 전면 재실행에서 같은 발화라 `_workspace_prev/` 오이동 위험 | -| 2026-08-03 | rebuild Phase 2에 **문서 1건당 producer 1기동** 명시 | ubisam-deliverable-rebuild | producer를 하나만 띄우면서 "문서 1건마다 qa"를 요구해 점진 검증의 관측점이 없었음 | -| 2026-08-03 | **"소비처 확인 의무" 절 신설** (열거형·개수 변경 시 grep) | docs/harness-ptop.md | 4라운드 연속 같은 유형의 자체 유발 회귀 — 값을 늘리고 읽는 쪽을 안 고침. 개별 결함만 고치면 재발하므로 절차를 명문화 | -| 2026-08-03 | 실행 모드 `이어서` 의 **소비처 신설** (전달부·`ptop-lead`를 3종→4종) | orchestrate-ptop-harness, ptop-lead | 신규 모드가 판별부에만 있고 소비처 0건 → 임의로 `전면` 매핑 시 재사용 대상 `01`이 `_workspace_prev/`로 사라짐 | -| 2026-08-03 | `_progress.md` 행 단위를 `{에이전트}:{문서}` 로 정정 | ubisam-deliverable-rebuild | "3행 고정"인데 문서 N건이면 인스턴스가 3N개 → 문서별 재시도 상한이 무력화 | -| 2026-08-03 | `AddSubMenu` 계수 규칙 정정 (26 → **활성 18**), 8탭 중 누락 4탭 행 추가 | ptop-deliverables/references/source-map.md | 26건에 주석 8건이 포함돼 형제 행(주석 제외 규칙)과 상충. `OverView`·`DeviceView`·`SettingView`·`VisionView` 는 진실원 행 자체가 없었음(`OverView` 는 대응 항목 미확인으로 표기) | -| 2026-08-03 | `RegisterViews — 권한 레벨 포함` → **권한 필드 없음**으로 정정 | ptop-deliverables/SKILL.md | `AuthLevel` 을 참조 맵에서 지웠으나 STEP 1이 여전히 추출을 명령. STEP 1이 참조 맵보다 먼저 읽힌다 | -| 2026-08-03 | `doyeon_note` 에 규약 바인딩(#3·#4·#9·#15·#16) 추가 | doyeon_note/SKILL.md | 유일하게 `rules.md` 인용 0건. 작업일지는 나중에 사실 기록으로 인용되므로 추론 혼입 위험이 크다 | -| 2026-08-04 | **19R 수정 패스.** `MainMenu` `PermissionLevel` 인자 존재로 정정(18R N-1 오정정 되돌림) | ptop-deliverables/SKILL.md·source-map.md | `AddSubMenu`(2인자)만 보고 "권한 필드 없음"이라 선언했으나 `EquipmentSetup.cs:261,266,289,302,310,318,323,330` 8건이 값 보유. 소비처(`09-pptx-integration.md:55`·`build_02설계_pptx.py:92`)의 `권한` 열이 굶고 있었음 | -| 2026-08-04 | §C 8탭 3중 모순 해소 + **상위 진실원 명시** | source-map.md | `VisionView`→`(해당없음)`(`EquipmentSetup.cs:342-343` 주석 확인), `OverView` 진실원→`docs/architecture.md`, `DeviceView`→Monitoring 3뷰 병기. 탭 목록의 진실원이 `05-form-schemas.md:78-85` 임을 명문화 | -| 2026-08-04 | `.gitignore` negation 주석을 **실측대로 정정**(git 전용, ripgrep 무효) | .gitignore, ubisam-qa.md | negation 투입 후에도 `rg --files .claude`=1 / `--no-ignore`=57. 주석대로 믿으면 다음 감사관이 `Grep path:".claude"` 를 재신뢰 | -| 2026-08-04 | `_workspace/`(경로 명시 시 정상) ↔ `.claude/`(루트 시작점이면 프루닝) **증상 분리** | harness-ptop.md, ubisam-qa.md | 두 증상을 같은 원인으로 묶어 진단하던 문구가 `_workspace/`에 불필요한 `--no-ignore` 를 요구 | -| 2026-08-04 | `알려진 한계 2가지`→`3가지` + 소비처 표에 **"자기 문단의 리드 개수어"** 행 신설 | harness-ptop.md | 5라운드 연속 미수정. 개별 수정으로는 안 끊겨 회귀 유형 자체를 표에 등재 | -| 2026-08-04 | Ubisam Phase 1·2 전달 항목에 **실행 모드 추가**, 3인에 모드 수신 규칙 이식 | rebuild/SKILL.md, ubisam-analyst·producer·qa | 모드 판별이 승인 목록 산정에만 쓰이고 이동·재사용 결정에 도달하지 못했음(`이어서` 소비처 0건) | -| 2026-08-04 | `이어서`·`부분`이면 **기동 대상도 축소**한다는 규칙 신설 | orchestrate/SKILL.md | 모드가 바꾸는 것이 이동 여부뿐이라 "없는 것만 생성" 정의가 미시행 | -| 2026-08-04 | `SendMessage` **`summary` 필수** 명시(에이전트 6) + Phase 3 developer `run_in_background: true` | 에이전트 6, orchestrate/SKILL.md | 실제 스키마상 `summary`는 필수이고 `to:"main"`은 백그라운드 전용 — 전경 기동 시 회신 경로가 막힘 | -| 2026-08-04 | 단독 기동 stale 절·`rules.md` #1 을 형제 스킬 2종에 이식 | analyze-ptop-implementation, optimize-ptop-build, analyze-ptop-architecture | "빌드 분석만 다시"가 후속 트리거인데 표기 주체가 `analyze-ptop-architecture` 에만 있었음 | -| 2026-08-04 | `PLCContoller.Config.cs` 역할 정정, `DefineConstants` 단정에 **PTOP csproj 기준** 한정 | ptop-developer.md, build-devops-engineer.md | 전자는 18줄 빈 파일인데 "주소 맵핑"으로 안내(형제 문서와 정반대). 후자는 저장소 전체에 `_NO_USE_*`·`USE_COGNEX` 가 실재하는데 에이전트가 자기 스킬보다 넓게 단정 | -| 2026-08-04 | **모션 보드 벤더 주의문을 IO 보드로 정정** | source-map.md | `eIOBoardType`(Ajin·PAIX·ACS)은 `AuroraIO/IODevice.cs:18` 소속이고 `AuroraMotionBoard` 는 `Ajin/` 구현뿐 — 금지문이 IO와 모션을 혼동해 `architecture.md:133` 을 거짓 위반으로 만들고 있었음 | -| 2026-08-04 | 디바이스 "5종 전수" → **활성 3 + 주석 3(상태감시는 살아 있음)** | ptop-lead.md | 활성 `registry.Register` 3건인데 5종 파악을 요구. `AddDeviceActiveStatus`(`:70-71`) 때문에 "미사용" 단정도 불가 | -| 2026-08-04 | `render_helpers.py` 크래시 수정 + 출력 경로·실행 예 정정 | ui_layout_image/render_helpers.py | `os.makedirs('')` → `FileNotFoundError`(파일명만 준 경우). `_demo.png` 가 스킬 폴더로 새고 있었고 docstring 이 맨 파일명 실행을 지시 | -| 2026-08-04 | 유형 뱃지 중복 2행 삭제(11→**9**), `TODAY` 출처 정정, ppt spec 예시 실명 제거 | design-system.md, 05-form-schemas.md, ubisam-ppt-make/SKILL.md | 뱃지가 enum 9종과 불일치, `TODAY`는 `xlsxfill.py` 가 아니라 `build_02설계_xlsx.py:41`, spec 예시의 타 프로젝트 조직·담당자가 복사 유발 | -| 2026-08-04 | `README.md` 디자인 지시를 §7 부재에 맞게 재작성 | ubisam-deliverables/SKILL.md | `08-design-system.md:98` §7 은 `_task.md` 전용 — README 골격이 없는데 적용을 명령 | -| 2026-08-04 | **200줄 상한 복구** — 변경 이력 분리, 보고서 골격·프로토콜을 `references/` 로 | harness-ptop.md, orchestrate/SKILL.md, rebuild/SKILL.md | 감사 중 수정으로 202·201줄 발생(`rules.md` #4 자기 위반). 본 파일도 200줄에 도달해 이력 추가가 불가능했음 | -| 2026-08-04 | **20R.** `부분` 모드를 기동 축소 조건에서 제외 + 생략 시 완료 판정 대체 규칙 신설 | orchestrate/SKILL.md, references/mode-rules.md | **19R 수정이 만든 seam(A·B 둘 다 Major 지목).** `부분`은 지목 에이전트를 *다시 돌리는* 모드인데 산출물이 있다는 이유로 생략해 **0기동**이 됐고, `이어서`에서 lead를 생략하면 Phase 3이 오지 않을 알림을 무기한 대기했다 | -| 2026-08-04 | `PLCContoller.Config.cs` 역할 정정을 **`analyze-ptop-architecture` 에도** 반영 | analyze-ptop-architecture/SKILL.md | 19R이 `ptop-developer.md` 만 고치고 같은 서술의 **다른 사본**을 놓쳤다. 하필 `ptop-lead` 가 "먼저 읽는다"고 지정한 스킬 | -| 2026-08-04 | 하네스 문서 상호 인용을 **라인 번호 → 앵커 문자열**로 전환 | source-map.md, harness-ptop.md | `05-form-schemas.md:78-85` 가 같은 배치의 2줄 추가로 어긋나 정정 대상 `VisionView` 를 범위 밖으로 밀어냈다. 소비처 표에 "라인 드리프트" 행 신설 | -| 2026-08-04 | 조건부서식 상수 소재 정정 (`xlsxfill.py` 에 **없다** — 관련 API 0건) | 00-harness.md | 계약 문서가 `ubisam-producer.md` 와 정반대를 적었고, 계약이 먼저 읽힌다 | -| 2026-08-04 | 박제된 `rg` 실측치(57) → **재현 명령과 관계(1 ≪ 전체)** 로 교체 | harness-ptop.md, ubisam-qa.md, .gitignore | 파일이 늘어 59가 되며 드리프트. 숫자를 문서에 박는 구조 자체가 원인이라 숫자를 없앴다 | -| 2026-08-04 | `test-scenarios` 개수 선언 `1+1` → **4흐름**, `_progress.md` 행 초기화에 `생략` 상태 추가 | orchestrate/SKILL.md | 19R이 신설한 "리드 개수어" 규칙의 자기 위반. 축소 기동과 3행 초기화가 미정합 | -| 2026-08-04 | Ubisam producer·qa 기동에 `run_in_background: true` | rebuild/SKILL.md | `to:"main"` 은 백그라운드 전용인데 19R이 PTOP Phase 3 에만 적용 | -| 2026-08-04 | 디바이스 5종 나열 잔여분 정정, 200줄 문구 앵커 5건, `build_deck.py`·`showcase.json` 실명 20건 → 플레이스홀더, `__pycache__` 3건 삭제 | ptop-lead.md 외 8건 | 19R 정정이 같은 파일 앞부분·형제 파일에 남긴 잔여 | -| 2026-08-04 | 모드 규칙을 `references/mode-rules.md` 로 분리 (208 → 200줄 이하) | orchestrate/SKILL.md | 위 수정으로 `rules.md` #4 재위반 | -| 2026-08-04 | **21R.** 원장 상태 enum **정의부**에 `생략` 추가 (3 → 4종) | references/data-protocol.md, orchestrate/SKILL.md, mode-rules.md | **20R 수정이 쓰는 쪽(Phase 분기)만 고치고 정의부를 안 고쳤다** — A·B 둘 다 지목. 정의부에 없으면 기록 주체가 애초에 안 적어 19R 교착이 재발한다 | -| 2026-08-04 | `생략` 을 **모드 무관 "이번 실행에서 기동하지 않음"** 으로 일반화 | data-protocol.md, mode-rules.md, orchestrate/SKILL.md | `이어서` 에만 부여돼 `부분` 의 미지목 에이전트 상태가 미정의였고, Phase 4 생략 분기가 안 걸려 교차 질문이 불필요하게 `미검증` 으로 떨어졌다 | -| 2026-08-04 | 생략 대상 표에 `ptop-developer` 추가 (2인 → **3인 전원**) | mode-rules.md | lead·build만 열거해 `이어서` 에서 developer 가 중복 기동 | -| 2026-08-04 | 마지막 `.md:NN` 상호 인용을 앵커로 전환 — **살아 있는 라인 인용 0건** | source-map.md | 20R이 세운 앵커 정책의 유일한 미적용 지점. 이로써 라인 드리프트 결함 유형이 종료된다 | -| 2026-08-04 | **"열거형 정의부 먼저" 규칙 신설** (① 정의한 표 → ② 기록하는 곳 → ③ 읽는 곳) | docs/harness-ptop.md | 6라운드 연속 같은 유형이 재발한 근본 원인. 개별 결함만 고쳐서는 안 끊겨 순서를 명문화 | -| 2026-08-04 | `xlsxfill.py` 타 프로젝트명(공소수정기·FMM) 제거 + 맨 파일명 실행 지시 정규화 | references/xlsxfill.py | 형제 3곳은 이미 전체 경로로 정규화됐는데 이 파일만 남아 있었다 | -| 2026-08-04 | rebuild qa 기동 문장에 `run_in_background: true` (잔여 seam) | rebuild/SKILL.md | 20R이 규칙은 넣고 **같은 파일의 재기술 문장**을 안 고쳤다 | -| 2026-08-04 | `build-devops-engineer` 자기모순 해소 ("lead 지시 대기 안 함" ↔ "lead 지시에 따라 수행") | build-devops-engineer.md | 기동 주체가 오케스트레이터 전담으로 바뀐 뒤 §역할 문구가 옛 전제를 유지 | -| 2026-08-04 | **22R.** Phase 3에 **developer 자신을 생략하는 분기** 신설 | orchestrate/SKILL.md, mode-rules.md | **21R 수정이 위임만 하고 수신처를 만들지 않았다**(A·B 둘 다 Major). `mode-rules.md` 가 "Phase 3에서 판단"으로 넘겼는데 Phase 3에 분기가 0건 → `생략` 으로 적어 둔 developer 가 실제 기동돼 원장이 거짓이 되고 `02`·`03` 을 덮어썼다 | -| 2026-08-04 | Phase 4를 **`완료`/`실패`/`생략` 3분기**로 분리 | orchestrate/SKILL.md, references/collection-rules.md | "실패·미기동"을 한 처리로 묶어 `부분`·`이어서` 실행이 **매번** 교차 질문 2건을 통째로 `미검증` 으로 떨어뜨렸다. `생략` 은 산출물이 실재하므로 파일을 읽어 답할 수 있다 | -| 2026-08-04 | 성공 기준의 `미검증` 대체 조건에 `생략` 경로 추가 | orchestrate/SKILL.md | "실패했으면"만 허용해 `부분` 실행이 **자기 성공 기준을 충족할 수 없었다** | -| 2026-08-04 | 기동 축소 기준을 **모드별로 분리 서술** (`이어서`=산출물 유무 / `부분`=지목 여부) | orchestrate/SKILL.md, mode-rules.md | 본문이 "`부분`에는 적용하지 않는다"로만 적혀 §Phase 1-5의 `생략` 기록 지시와 표면 모순으로 읽혔다 | -| 2026-08-04 | 앵커 오지정 정정 — `ubisam-format-map` §5 → **§6** | source-map.md | 21R이 라인 인용을 앵커로 바꾸며 절 번호를 확인하지 않았다. **앵커 전환도 검증이 필요하다**는 실증 | -| 2026-08-04 | `test-scenarios.md` 부분 재실행 흐름에 **원장 `생략` 기록·Phase 3 스킵·Phase 4 3분기** 단계 추가 | references/test-scenarios.md | `생략` 분기의 유일한 end-to-end 검증점이 비어 있었다 | -| 2026-08-04 | `build-devops-engineer` `(Phase 3 의존)` 잔여 정정, rebuild analyst 기동에 `run_in_background` | build-devops-engineer.md, rebuild/SKILL.md | build 는 Phase 2 병렬로 선행 의존이 없다(복붙 잔재). analyst 는 단일 문서 시 회신이 막혔다 | -| 2026-08-04 | **소비처 확인 의무에 ④ "위임했으면 수신처 확인" + 앵커 전환 시 `grep -n "^## "` 절차** 신설 | docs/harness-ptop.md | 21R의 순서 규칙(①정의→②기록→③읽기)이 "정의부 누락" 유형은 잡았으나, **위임 문자열의 수신처 부재**는 못 잡았다 | -| 2026-08-04 | Phase 4 상세를 `references/collection-rules.md` 로 분리 (213 → 200줄) | orchestrate/SKILL.md | 위 수정으로 `rules.md` #4 재위반 | -| 2026-08-04 | **23R(최종 수정, 미채점).** `_workspace_prev/` 이동 주체 모순 해소 — 에이전트 정의를 **전면 금지**로 통일 | ptop-lead.md, ubisam-analyst.md, orchestrate/SKILL.md | **B 최상위 결함(잠재 데이터 유실).** 오케스트레이터 문서는 "팀원은 안 한다"인데 lead·analyst 는 "`전면`이면 옮긴다"로 정반대였다. 금지문이 구속 대상의 독서 경로 밖이라 수신처 0건 → 이중 이동 시 병렬로 쓰이던 `04`~`06` 이 딸려간다 | -| 2026-08-04 | 모드 판별표를 **두 축(산출물 상태 × 요청 범위)으로 분리** + `생략`인데 파일 부재 시 분기 추가 | references/mode-rules.md | 1열이 두 축을 섞어 **산출물 0건 + "아키텍처만 다시"** 가 `초기`·`부분` 양쪽에 매치했다(현재 저장소가 정확히 그 상태) | -| 2026-08-04 | 파일 이동으로 끊긴 인용 복구 — 교차 확인 질문 정의처를 `collection-rules.md` §교차 확인 질문으로 | ptop-lead.md | **22R의 파일 분리가 끊은 인용.** 답할 주체가 지목된 곳(`SKILL.md` Phase 4)을 열면 질문이 없었다 | -| 2026-08-04 | 복붙 쌍둥이 자기모순 해소 — `ptop-developer.md` "lead 지시를 기다리지 않는다" ↔ "lead 지시를 받아 수행" | ptop-developer.md | 22R이 `build-devops-engineer.md` 만 고치고 세 줄 간격의 쌍둥이를 놓쳤다 | -| 2026-08-04 | `mode-rules.md` 리드 문장을 표와 정합("`이어서`에서만" → 모드별 기준), Phase 3 전방 참조, 승인 ④에 stale 편집 편입 | mode-rules.md, orchestrate/SKILL.md | 표는 고쳤는데 그 위 요약문이 옛말로 남아 정면 충돌. 무조건 기동 문장이 생략 분기보다 앞. stale 편집이 승인 4항 어디에도 없었다 | -| 2026-08-04 | `이어서` 수신 블록을 `ptop-developer`·`build-devops-engineer` 에 신설 | 에이전트 2 | Phase 2가 모드 4종을 전원에게 전달하는데 수신 블록은 lead 에만 있었다(문자열 각 0건) | -| 2026-08-04 | **⑤~⑦ 재발 방지 규칙 신설** + 앵커 검출 명령을 `^#{2,4} \|^> \*\*` 로 확장 | docs/harness-ptop.md | ⑤ 금지·전담 지정 시 그 주체의 정의 파일 확인 ⑥ 절을 옮겼으면 제목을 `grep -rn` ⑦ 리드 문장·복붙 쌍둥이 동반 수정. `grep -n "^## "` 로는 하네스 자신의 앵커 4종이 검출되지 않았다 | -| 2026-08-04 | `harness-ubisam.md` 200줄 문구 앵커 부착·자기 서술 정정, `protocol.md` 베어 `_workspace/` 경로 명시 | harness-ubisam.md, protocol.md | 21R P3 2R 연속 미이행. PTOP 하네스의 동명 폴더와 혼동 소지 | diff --git a/docs/harness-ptop.md b/docs/harness-ptop.md deleted file mode 100644 index 7dc7e8b..0000000 --- a/docs/harness-ptop.md +++ /dev/null @@ -1,192 +0,0 @@ -# 하네스: ILSOS_PrismaticRD_PTOP 분석 팀 - -## 목표 - -ILSOS_PrismaticRD_PTOP(PtoP)의 3계층 아키텍처, 구현 상세, 빌드 최적화를 종합 분석하고 개선안 제시. -**분석 전용 하네스** — 소스 코드를 수정하지 않는다. 코드를 실제로 고치는 작업은 `code_Agent`를 쓴다. - -## 트리거 - -다음 요청 시 `orchestrate-ptop-harness` 스킬을 사용한다. - -- "PTOP 프로젝트 전체 분석" / "PTOP 전체 점검" / "PTOP 구조 파악" -- "PTOP 아키텍처와 구현 분석" / "PTOP 팀 조율" -- 후속: "PTOP 재분석", "아키텍처만 다시", "빌드 분석만 다시", "이전 결과 기반으로" - -단일 영역만 필요하면 개별 스킬을 직접 쓴다 — `analyze-ptop-architecture` / -`analyze-ptop-implementation` / `optimize-ptop-build`. - -## 팀 구성 - -| 에이전트 | 담당 | 사용 스킬 | 산출 (`_workspace/`) | -|---|---|---|---| -| `ptop-lead` | 3계층 아키텍처·디바이스 스택·시퀀스 의존성 | `analyze-ptop-architecture` | `01_ptop_architecture.md` | -| `ptop-developer` | 시퀀스 상태머신·타이밍·Rx 체인·에러 처리 | `analyze-ptop-implementation` | `02_ptop_implementation.md`, `03_device_integration.md` | -| `build-devops-engineer` | 멀티 구성 빌드·의존성·CI/CD | `optimize-ptop-build` | `04_build_analysis.md`, `05_cicd_pipeline.yml`, `06_ptop_build_optimization.md` | - -통합 보고서: `_workspace/00_PTOP_HARNESS_SUMMARY.md` - -## 실행 모드 - -**서브 에이전트 병렬 + 의존 순차.** 이 환경에는 `TeamCreate`/`TeamDelete` 도구가 없으므로 -`Agent`(기동, `model: "opus"`) + `SendMessage`(소통) + `_workspace/_progress.md` 파일(진행 원장)로 구성한다. - -`ptop-lead`와 `build-devops-engineer`는 병렬, `ptop-developer`는 lead 산출 완료 후 순차. - -## 구성 요소 - -**Agents:** `.claude/agents/ptop-lead.md`, `ptop-developer.md`, `build-devops-engineer.md` -**Skills:** `.claude/skills/orchestrate-ptop-harness/`, `analyze-ptop-architecture/`, -`analyze-ptop-implementation/`, `optimize-ptop-build/` -**Workspace:** `_workspace/` (중간 산출물 보존 — 감사 추적용) - -## 하네스를 고칠 때 — 소비처 확인 의무 - -**라운드마다 같은 유형의 회귀가 반복됐다.** 값을 늘려놓고 그 값을 읽는 쪽을 안 고치는 것이다. - -| 실제 사례 | 늘린 것 | 안 고친 소비처 | -|---|---|---| -| `ubisam-qa` 검증항목 11 신설 | 표 행 10 → 11 | 성공 기준 "10개" | -| `[추론]` 바인딩 확대 | 인용 17 → 19 | 역인덱스 표의 숫자 | -| 실행 모드 `이어서` 신설 | 모드 3 → 4종 | 전달부·`ptop-lead` 소비부 (둘 다 3종) | -| 문서 1건당 producer 1기동 | 인스턴스 3 → 3N | `_progress.md` "3행" 초기화 | -| 검색식 함정 항목 추가 | 한계 2 → 3항 | **같은 문단의 리드 개수어** `알려진 한계 2가지` | -| 표에 행 2개 추가 | 표가 2줄 아래로 밀림 | **그 표를 `파일:라인` 으로 가리키던 인용** (가리키는 범위가 어긋남) | -| Phase 2에 기동 축소 규칙 신설 | 기동 대상 3 → 3−N | Phase 3·4의 **완료 알림 대기**(생략된 에이전트는 알림을 안 보낸다) | -| 원장에 `생략` 상태 신설 | 상태 3 → 4종 | **그 상태를 정의한 표**(`data-protocol.md` 진행 원장) — 정의부에 없으면 기록 주체가 안 적는다 | - -> **열거형에 값을 추가했으면 그 열거형을 *정의한 표*를 먼저 고친다.** 6라운드 연속 같은 유형이 -> 재발한 이유는 늘 **쓰는 쪽(Phase 분기)만 고치고 정의부를 안 고쳤기** 때문이다. -> 정의부에 없는 값은 **기록 주체가 애초에 적지 않으므로** 소비처가 아무리 정확해도 동작하지 않는다. -> 순서: ① 정의한 표 → ② 기록하는 곳 → ③ 읽는 곳 → **④ 위임했으면 수신처.** 넷을 **같은 편집에서** 본다. -> -> **④ 위임의 수신처 확인.** `(Phase 3에서 판단)`·`(위 참조)`·`(§X 참조)` 처럼 **처리를 다른 곳으로 -> 넘기는 문자열을 썼으면, 그 수신처를 열어 해당 분기가 실재하는지 확인**한다. 위임은 소비처를 -> *지정*할 뿐 *만들지* 않는다 — 수신처가 없으면 그 규칙은 문서에만 있고 실행되지 않는다. -> 실제 사례: `mode-rules.md` 가 developer 생략을 "Phase 3에서 판단"으로 넘겼는데 Phase 3에 분기가 -> 0건이라, `생략` 으로 적어 둔 에이전트가 실제로 기동돼 원장이 거짓이 됐다. -> -> **앵커로 인용을 바꿀 때는 대상 파일에서 절 제목을 즉시 확인한다.** 라인 번호를 앵커로 바꾸면 -> 드리프트가 없어지지만, **앵커 자체를 잘못 적으면 같은 오류가 난다**(실제로 `§5` 로 적었으나 -> 대상 문장은 `§6` 이었다). -> ⚠ `grep -n "^## "` 만으로는 부족하다 — 하네스는 `###` 소제목과 **인용문 안의 굵은 소절 제목** -> (`> **…**`)도 앵커로 쓴다. 다음처럼 넓게 뜬 뒤 눈으로 고른다: -> -> ```bash -> grep -nE "^#{2,4} |^> \*\*" <대상파일> -> ``` -> -> **⑤ 어떤 주체를 금지·전담으로 지정했으면 그 주체의 정의 파일을 연다.** 오케스트레이터 문서에만 -> "팀원은 하지 않는다"를 적고 에이전트 정의에 반대말이 남으면, **구속 대상이 그 금지문을 읽지 않는다.** -> 실제 사례: `_workspace_prev/` 이동을 "오케스트레이터 전담"으로 정해 놓고 `ptop-lead`·`ubisam-analyst`에 -> "`전면`이면 옮긴다"가 남아 이중 이동으로 병렬 산출물이 딸려갈 상태였다. -> -> **⑥ 절을 다른 파일로 옮겼으면 그 절 제목을 `grep -rn` 해 인용처를 전부 연다.** 라인→앵커 전환은 -> 라인 드리프트를 없애지만 **절의 파일 이동은 앵커도 무력화한다.** 실제 사례: 교차 확인 질문을 -> `collection-rules.md`로 옮긴 뒤 `ptop-lead`가 여전히 `SKILL.md` Phase 4를 지목해, 답할 주체가 -> 지목된 곳을 열면 질문이 없었다. -> -> **⑦ 고친 문장의 형제를 함께 본다** — 참조 문서의 **리드 문장**(표는 고쳤는데 그 위 요약문이 옛말), -> 그리고 **복붙 쌍둥이 파일**(에이전트 정의 6종은 서로 문단을 복사해 쓴다). 한쪽만 고치면 -> 세 줄 간격으로 자기모순이 남는다. - -> **자주 재발하는 두 가지.** -> ① **자기 문단이 스스로 개수를 선언하는 말**(`N가지`·`N종`·`N개`·`N건`·`N행`)은 항목을 -> 추가·삭제할 때 **같은 편집에서** 고친다. 항목 밑에 ①②③ 을 붙이는 순간 그 문단은 개수 소비처를 갖는다. -> ② **다른 파일을 `파일:라인` 으로 가리켜 놓고 그 파일을 늘리면 인용이 조용히 어긋난다.** -> 같은 배치에서 A를 고치고 B가 A를 가리키면 **B의 라인 번호를 다시 확인**한다. -> -> **드리프트를 없애는 방법: 라인 번호 대신 앵커 문자열로 가리킨다.** -> `05-form-schemas.md:78-85` 대신 `05-form-schemas.md §C 의 8탭 표` 처럼 쓰면 파일이 늘어나도 -> 인용이 살아 있다. 소스 코드(`.cs`)는 라인 번호가 유일한 수단이라 예외지만, -> **하네스 문서끼리는 앵커를 쓴다.** - -그래서 **열거형 값·항목 수·인스턴스 수를 바꿨으면 반드시 소비처를 검색한다.** - -```bash -# 예: 옛 열거를 그대로 쓰는 곳이 남았는지 / 새 값의 소비처가 정말 있는지 -grep -rn "초기/부분/전면" .claude -grep -rn "이어서" .claude -``` - -> ⚠ **`.claude/` 를 검색할 때는 하위 폴더를 직접 지정해야 한다** (실측 확인). -> `.gitignore:39` 의 `.claude/*` 때문에 ripgrep(= **`Grep` 도구**)이 `.claude` 를 통째로 건너뛴다. -> -> | 검색 시작점 | 결과 | -> |---|---| -> | 저장소 루트 · `.claude` | **0건 — 에러 없이 조용히 실패** | -> | `.claude/agents` · `.claude/skills` | 정상 | -> -> 따라서 `Grep` 도구는 `path: ".claude/skills"` 처럼 **하위를 지정**해 두 번 돌리고, -> 셸을 쓸 때만 `grep -rn ... .claude`(bash grep은 무시 규칙을 안 본다)가 한 번에 된다. -> **이 절의 예시 명령이 `Grep` 도구가 아니라 Bash `grep -rn` 인 것은 그 때문이다 — 바꾸지 말 것.** -> -> `.gitignore` 의 negation 2줄은 **git 추적만 되살리고 ripgrep 프루닝은 되살리지 못한다** -> (재현: `rg --files .claude` 는 **1건**(`settings.json` 뿐)이고 `rg --files --no-ignore .claude` 는 -> 전체를 센다. `rg --files .claude/skills` 도 정상. **숫자는 파일이 늘면 변하므로 박제하지 말고 -> 명령을 돌려 비교한다** — 판정 근거는 `1 ≪ 전체` 라는 관계다.) -> -> `_workspace/` 도 무시 대상이지만 **경로를 명시하면 rg가 정상 탐색한다**(`rg --files _workspace` = -> `--no-ignore` 와 동수). 즉 `--no-ignore` 가 필요한 것은 **루트에서 glob 으로 훑을 때**이며, -> `.claude` 는 경로를 명시해도 루트 시작점이면 프루닝된다 — 둘은 다른 증상이다. - -판정: **새 값이 정의부에만 있고 소비처가 0건이면 그 값은 동작하지 않는다.** -단, 위 함정 때문에 **0건을 보면 검색 시작점부터 의심한다** — 죽은 값과 못 찾은 값은 다르다. -개수를 문서에 적을 때는 그 개수의 진실원(표·파일 목록)과 **같은 편집에서** 함께 고친다. - -## 규칙 ↔ 바인딩 역인덱스 - -`rules.md` 조항이 하네스에서 실제로 시행되는지 점검하는 표다. **조항을 추가하면 이 표도 갱신한다** — -바인딩 누락이 3라운드 연속 감사 지적으로 나온 패턴이라 자가 점검 수단을 둔다. - -자가 점검 (조항별 인용 건수를 센다): - -```bash -grep -rhoE "rules\.md.{0,20}" .claude docs CLAUDE.md \ - | grep -oE '#[0-9]+' | sort -t'#' -k2 -n | uniq -c -``` - -> **검색식 함정 2가지 (둘 다 실측 확인).** -> ① 실제 표기는 `` `rules.md` #2 `` 라 **백틱이 사이에 낀다.** `rules\.md\s*#` 로 찾으면 **0건**이 나온다. -> ② 뒤 범위를 `.{0,3}` 로 좁히면 `#15·#16` 같은 복합 인용에서 **뒤 번호를 놓친다**(#16이 1건으로 보임). -> 문자클래스로 `·`(U+00B7)를 넣는 우회도 안 된다 — 멀티바이트라 `grep -E` 브래킷에서 깨진다. -> 그래서 뒤 20자를 통째로 떠서 `#N`을 전부 뽑는다. -> **0건·급감이 보이면 미바인딩이 아니라 검색식부터 의심한다** (`rules.md` #15). -> 알려진 한계 3가지: ① `#11~13` 은 `#11` 로만 집계된다(범위 표기). ② 앞 20자 안에 `rules.md` 가 -> 없는 맨 `#N` 표기는 집계되지 않는다 — 그래서 **바인딩할 때는 반드시 `rules.md` 를 함께 쓴다.** -> ③ 위 명령이 **Bash `grep`** 인 것은 `Grep` 도구가 `.claude` 를 프루닝하기 때문이다(위 §소비처 확인 의무). -> 도구로 바꾸면 `.claude` 몫이 통째로 빠져 전 조항이 급감한다. - -| 조항 | 요지 | 바인딩되어야 할 곳 | -|---|---|---| -| #1 | 주석·이름 맹신 금지 | 분석 스킬 3종 (조항번호 인용 + 문장 반영 병행) | -| #2 | 수정은 승인받기 | 승인 게이트를 가진 전 스킬·에이전트 | -| #3 | 한글 깨짐 방지 | PTOP 에이전트 3인 + 산출 스크립트를 실행하는 스킬 | -| #4 | `.md` 200줄 상한 | `.md` 산출물을 쓰는 에이전트 전원 | -| #5 | `@경로` 임포트 | `rules.md` 자체 (하네스는 인용하지 않아도 된다) | -| #6 | 완료 후 `.md` 갱신 확인 | 두 오케스트레이터 + 산출물 스킬 | -| #10 | 중간 진행 보고 | 두 오케스트레이터 + 분석 스킬 | -| #11~13 | 출력 색상 규약 | 에이전트 전원 + 사용자에게 보고하는 스킬 | -| #15·#16 | 추론 검증 · `[추론]` 표기 | 에이전트 전원 + 값·해석을 생성하는 스킬 (2026-08-03 신규) | - -> **이 표에 인용 건수를 적지 않는다.** 세 라운드 연속으로 "바인딩을 늘리고 표의 숫자를 안 고쳐 -> 표가 거짓이 되는" 회귀가 났다. 숫자가 필요하면 **위 명령을 그때 실행한다** — 표는 *어디에 -> 있어야 하는가*만 말하고, *몇 건인가*는 명령이 답한다. -> -> #7~9·#14는 세션 전역 규약이라 하네스가 개별 인용하지 않는다 — 미바인딩이 아니다. -> 조항이 표에 있는데 해당 위치에서 검색되지 않으면 그때가 미바인딩이다. - -## 변경 이력 - -표가 60행을 넘어 별도 파일로 분리했다 (`rules.md` #4) → [harness-ptop-changelog.md](./harness-ptop-changelog.md) -**하네스를 고쳤으면 그 파일에 행을 추가한다.** - -> **주의 1:** `.claude/agents/`에 파일을 추가·이동했거나 **`CLAUDE.md`·`@` 임포트 대상 문서를 고쳤다면** -> **세션을 재시작해야** 반영된다. 에이전트는 `Agent` 도구에 등록되지 않고, CLAUDE.md는 세션 시작 -> 시점의 판본이 계속 쓰인다 — 파일을 고쳐도 **현재 세션의 라우팅 가드는 옛날 것**이다. -> 디스크 내용과 실제 적용 내용이 다를 수 있다는 뜻이므로, 하네스를 고친 직후 검증할 때 주의한다. -> -> **주의 2:** 에이전트 frontmatter에 `tools:`를 넣어 쓰기 도구를 막지 **않았다.** 여섯 에이전트 모두 -> **각자의 작업공간**(PTOP 3인 = 저장소 루트 `_workspace/`, Ubisam 3인 = `docs/[Ubisam산출물]/_workspace/`)에 -> `.md` 산출물을 직접 쓰기 때문이다. "분석 전용"은 *소스 코드를 고치지 않는다*는 -> 뜻이며, 파일 쓰기 자체를 막으면 하네스가 아무 산출물도 만들지 못한다. diff --git a/docs/harness-ubisam.md b/docs/harness-ubisam.md deleted file mode 100644 index 53ac7a3..0000000 --- a/docs/harness-ubisam.md +++ /dev/null @@ -1,102 +0,0 @@ -# 하네스: Ubisam 산출물 - -## 목표 - -프로젝트 산출물을 Ubisam 협업관리(칸반) 6단계 양식으로 구성·생성·재생산·검증한다. -산출물 트리는 `docs/[Ubisam산출물]/` 하위에 미러링한다(로컬 전용 — `.gitignore` 제외 대상). - -## 트리거 — 어느 스킬을 쓰는가 - -입력이 무엇이냐로 갈린다. - -| 입력 | 요청 예시 | 스킬 | -|---|---|---| -| **없음** (트리부터) | "산출물 구조 만들어줘", "트리 스캐폴딩" | `ubisam-deliverables` | -| **PTOP 소스코드** | "소스 기준으로 설계 산출물 최신화", "PLC 신호정의서 갱신" | `ptop-deliverables` | -| **기존 타사 문서** | "이 xlsx를 Ubisam 양식으로 바꿔줘", "타사 산출물 재생산" | `ubisam-deliverable-rebuild` | -| **조회만** | "상태 enum이 뭐였지", "6단계 슬롯 알려줘" | `ubisam-format-map` | - -렌더링 전용 스킬: `.pptx` → `ubisam-ppt-make`, `.docx` → `ubisam-docx`(**사용자 전역 스킬 — 이 저장소에는 없음**), -화면 도식 이미지 → `ui_layout_image`. - -## 재생산 하네스 팀 구성 (`ubisam-deliverable-rebuild`) - -| 에이전트 | 담당 | 산출 (`docs/[Ubisam산출물]/_workspace/`) | -|---|---|---| -| `ubisam-analyst` | 원본 구조 해부·타설비 잔재 식별·6단계 슬롯 매핑 | `01_analyst_{문서}.md` | -| `ubisam-producer` | 매핑표대로 xlsx·pptx·md 재생산·출처 기입 | `02_producer_{문서}.md` + 산출물 파일 | -| `ubisam-qa` | 원본↔매핑표↔산출물 교차 대조·enum·잔재·출처 검증 | `03_qa_{문서}.md` | - -**실행 모드:** 서브 에이전트 + **점진적 생성-검증 루프**. -producer가 문서 1건을 끝낼 때마다 qa가 즉시 검증한다 — 구조적 결함이 늦게 발견되면 -이후 산출물 전부를 되돌려야 하기 때문이다. - -기동은 `Agent`(`model: "opus"`), 소통은 `SendMessage`, 진행 공유는 `_progress.md` 파일. -이 환경에 `TeamCreate`/`TeamDelete`는 없다. - -## 불변 규칙 - -- **enum 고정** — 상태 4종·유형 9종은 `ubisam-format-map`이 단일 기준. 임의 변형 시 칸반 조건부서식이 깨진다. -- **출처 명시** — 채운 값마다 `— 출처: 파일:심볼`. qa가 이걸로 검증한다. -- **추측 금지** — 진실원이 없으면 `(제안)` 또는 `미정 — 확인 필요`. -- **추론 표기** — 확인 전 서술은 문장 앞에 `[추론]` (`rules.md` #15·#16). 아래 축으로 구분하며 - `[추론]`은 나머지를 **대체하지 않는다**(필요하면 병기): - - | 상황 | 표기 | - |---|---| - | 원본·소스로 확인함 | `— 출처: 파일:심볼` (표기어 없음) | - | 확인했으나 값이 없음·측정 못 함 | `미측정` · `불명확 — 확인 필요` · `미검증` · `미확인` | - | 확인 전 서술 · 검증 불가 | 문장 앞 `[추론]` (구 `(추정)` 을 대체) | - | 진실원 자체가 없음 | `(제안)` · `미정 — 확인 필요` | -- **비침습** — `docs/[Ubisam산출물]/` 밖은 읽기만. 소스·`CLAUDE.md`·루트 규칙 파일 수정 금지. -- **MD 200줄 상한** (`rules.md` #4) — 초과 시 분할 + 상대경로 링크. -- **UTF-8** — 스크립트 실행은 `PYTHONUTF8=1 py