LGES-OC5-PtoP-Welder/docs/harness-ptop.md
2026-08-06 11:29:00 +09:00

193 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 하네스: 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` 산출물을 직접 쓰기 때문이다. "분석 전용"은 *소스 코드를 고치지 않는다*는
> 뜻이며, 파일 쓰기 자체를 막으면 하네스가 아무 산출물도 만들지 못한다.