The .claude/skills check accepts both local layouts and fails on a dangling link. Review: round 1 (@e1ed270) claude agy grok PASS, codex NOT PASS (a dangling top-level link was skipped); fixed in 150b493; round 2 4/4 PASS. Reports and the round-2 identity sidecars go to .agents/reports/<session>/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
47 lines
4.2 KiB
Markdown
47 lines
4.2 KiB
Markdown
# PR #47 2회차 델타 리뷰 — 5f1a5a29
|
||
|
||
**PASS**. 이전 R1(깨진 최상위 skills 링크의 skip)이 해결됐고, 실제 검사와 같은 함수를 사용하는 합성 배치 테스트가 회귀를 잡는다. 새 반려 사유는 발견하지 못했다.
|
||
|
||
## 검증 identity와 범위
|
||
|
||
- loop: `loop-20261004T044643Z-1b1440`
|
||
- base: `e1ed2708d835d712f5f3a9dfd51b8f66ca1ac447`
|
||
- head: `150b4937f816c6407be16fc4c37ab88e478927e7`
|
||
- tree: `afce44d2e0f91720d81e8d7d484f0e1358dee680`
|
||
- 검증 cwd: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261004T044643Z-1b1440/1`
|
||
|
||
HEAD/tree 일치, 시작·종료 시 git status clean. 이번 한 커밋의 변경은 `tests/test_issue42_skill_blocks.py` 하나(59 insertions, 12 deletions)이며 제품 코드·버전 변경은 없다. `git diff --check e1ed270 HEAD` 통과.
|
||
|
||
## 이전 지적 판정
|
||
|
||
| 지적 | 판정 | 근거 |
|
||
|---|---|---|
|
||
| R1: `.claude/skills` 자체가 dangling symlink일 때 skip | **종결** | `tests/test_issue42_skill_blocks.py:248`이 exists와 is_symlink가 모두 False인 경우에만 None을 반환한다. 깨진 링크는 :250–252의 symlink 검사에서 문제 목록을 반환하고, 실제 테스트 :264–267이 이를 실패로 처리한다. |
|
||
|
||
## 검증 결과
|
||
|
||
검증 cwd에서 실행:
|
||
|
||
```sh
|
||
PYTHONDONTWRITEBYTECODE=1 /Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python -m pytest -p no:cacheprovider -q --basetemp=/tmp/5f1a5a29-selected tests/test_issue42_skill_blocks.py
|
||
```
|
||
|
||
**37 passed, 1 skipped in 0.06s**, rc 0. skip은 검증 트리에 원래 로컬 `.claude/skills`가 없기 때문이며, 새 합성 배치 6건은 모두 실행됐다.
|
||
|
||
- **같은 실제 경로로 전후 비교:** 검증 트리 안에 임시 `.claude/skills`를 존재하지 않는 대상의 symlink로 만들었다. base e1ed270에서 추출한 기존 함수는 같은 경로에서 SKIP했다. 현재 실제 pytest node는 **1 failed in 0.04s, rc 1**을 반환했다. 이 실패는 의도한 부정 탐침 결과이며 지정 모듈의 실패가 아니다.
|
||
- **회귀 테스트의 감도:** 현재 helper의 부재 조건만 메모리상 이전 `if not link.exists():`로 되돌린 뒤, 새 `test_claude_skills_layouts(..., "broken_top", False)`를 호출하면 AssertionError가 발생했다. 즉 새 회귀 테스트가 이전 결함을 검출한다.
|
||
- **정상 배치 유지:** 합성 `single`과 `per_skill`은 통과한다. 본 체크아웃의 스킬별 링크 배치에도 현재 helper를 읽기 전용으로 적용해 문제 목록 `[]`를 확인했다.
|
||
- **정리:** 임시 링크와 이번 탐침이 만든 부모 디렉터리를 finally에서 제거했다. 검증 트리의 로컬 배치 부재와 git clean 상태를 다시 확인했다.
|
||
|
||
독립 탐침은 `/tmp/5f1a5a29-probes.py`에 있다. 위 검증 cwd에서 `PYTHONDONTWRITEBYTECODE=1 <위 Python> /tmp/5f1a5a29-probes.py`로 재현한다. 전체 탐침 실행은 rc 0이며 base SKIP/current FAIL/조건 복원 시 합성 테스트 FAIL을 각각 확인한다. 체크아웃 소스는 변경하지 않았다.
|
||
|
||
## 합성 테스트와 범위 판단
|
||
|
||
`claude_skills_problems()`(:240–260)가 실제 로컬 배치 테스트(:264)와 합성 테스트(:294)의 공통 검사 함수다. 합성 테스트(:270–300)는 각각의 tmp_path 안에서 두 디렉터리 및 상대 symlink를 구성하고, 없음/단일 링크/개별 링크/잘못된 대상/깨진 최상위 링크/깨진 개별 링크를 직접 검사한다. 프로세스·시간·실제 사용자 배치에 의존하지 않아 결정적이다. 테스트 대상이 파일·디렉터리의 경로 해석이므로 합성 대상에 SKILL.md 본문을 만들지 않은 것도 적절하다.
|
||
|
||
기존 모듈의 8개 스킬 inventory 보장과 링크별 대상 비교는 유지됐다. 새로운 helper는 테스트 전용이며 제품 동작을 바꾸지 않는다. 기본 검사가 워크트리에서 skip되어도 합성 6건이 실행되므로 이번 수정의 핵심 조건은 더 이상 로컬 배치 유무에 가려지지 않는다.
|
||
|
||
본 체크아웃은 배치 읽기에만 사용했다. 실제 .mam.env·agent 세션·herdr 서버는 건드리지 않았고, 실제 .mam 쓰기는 지시된 lifecycle과 이 리포트에 한정했다. 재계획 승격은 필요 없다.
|
||
|
||
[VERDICT: PASS]
|