[Bug] orc_onboard --purge-conversation 의 claude 어댑터가 .jsonl 만 지우고 file-history·session-env 잔여물을 남기며 residual: none 으로 보고 #31

Closed
opened 2026-09-21 02:00:55 +00:00 by Godopu · 1 comment
Owner

증상

2026-09-21, 오케스트레이터 대화 1ad585a0-… 를 정리하면서 관측했다.

orc_onboard.sh --remove <uuid> --purge-conversation --yes --agent claude
# purged: ~/.claude/projects/<ws_key>/<uuid>.jsonl
# residual: none (agent: claude)

그러나 같은 UUID 로 된 항목 두 개가 디스크에 남아 있었다.

  • ~/.claude/file-history/<uuid>/ — 그 세션이 편집한 파일 이력 20개(92KB)
  • ~/.claude/session-env/<uuid>/ — 빈 디렉터리(4KB)

스킬이 residual: none 이라고 보고했기 때문에, 직접 find ~/.claude -name "*<uuid>*" 로 확인하지 않았다면 남은 것을 알 수 없었다. 두 항목은 수동으로 지웠다.

원인

  • lib_py/agents/adapters/claude.py:84-88 의 purge_artifacts 는 artifact_path(= <claude_dir>/<ws_key>/<uuid>.jsonl) 하나만 지운다.
  • claude 어댑터는 residual_artifacts 를 재정의하지 않는다. 그래서 base 기본 구현(lib_py/agents/base.py:189-192, "the default has nothing to scan" → [])이 쓰이고, 잔여물 유무와 무관하게 항상 빈 목록을 돌려준다.
  • 비교: agy 어댑터는 #10 에서 DB 사이드카(-wal/-shm/-journal)·brain/<uuid>·annotation·presence lock 까지 purge 하도록 고쳤고(adapters/agy.py:98-128), residual_artifacts 로 루트를 walk 해 같은 UUID 를 담은 경로를 보고한다(adapters/agy.py:130-). 현재 residual_artifacts 를 재정의한 어댑터는 agy 뿐이다.

영향

  • --purge-conversation 은 "복구 불가"를 전제로 안내하지만, claude 대화는 세션 부속 데이터가 남는다. file-history 에는 그 세션이 다룬 파일 내용 일부가 들어 있다.
  • 보고가 residual: none 이라 사용자가 남은 항목을 인지할 수 없다. 이는 #10 이 agy 에서 고친 것과 같은 계열의 빈틈이다.

제안

  1. claude 어댑터의 purge 대상에 ~/.claude/file-history/<uuid>/ 와 ~/.claude/session-env/<uuid>/ 를 추가한다(존재할 때만, 디렉터리 단위).
  2. claude 어댑터에 residual_artifacts 를 재정의해 ~/.claude 아래에서 UUID 를 포함하는 경로를 보고한다(agy 와 같은 방식, 범위는 claude_dir 상위로 한정).
  3. 나머지 어댑터(codex·grok·opencode·hermes)도 각 CLI 의 세션 부속 파일 위치를 확인해 같은 계약으로 맞춘다.
  4. 회귀 테스트: 임시 홈에 <uuid>.jsonl·file-history/<uuid>/·session-env/<uuid>/ 를 만든 뒤 purge 하고, 세 경로가 모두 사라지며 residual 보고가 비는지 검증한다.

관련

  • #10 agy 어댑터가 대화 부속 파일을 삭제하지 않던 문제(같은 계열)
  • #13 오케스트레이터 대화 purge 도입

환경 정보

  • main 1134d74(v4.6.0) 기준, 작업 브랜치 feat/issue-21-items-4-5-7
  • Claude Code v2.1.270, Linux
## 증상 2026-09-21, 오케스트레이터 대화 `1ad585a0-…` 를 정리하면서 관측했다. ``` orc_onboard.sh --remove <uuid> --purge-conversation --yes --agent claude # purged: ~/.claude/projects/<ws_key>/<uuid>.jsonl # residual: none (agent: claude) ``` 그러나 같은 UUID 로 된 항목 두 개가 디스크에 남아 있었다. - `~/.claude/file-history/<uuid>/` — 그 세션이 편집한 파일 이력 20개(92KB) - `~/.claude/session-env/<uuid>/` — 빈 디렉터리(4KB) 스킬이 `residual: none` 이라고 보고했기 때문에, 직접 `find ~/.claude -name "*<uuid>*"` 로 확인하지 않았다면 남은 것을 알 수 없었다. 두 항목은 수동으로 지웠다. ## 원인 - `lib_py/agents/adapters/claude.py:84-88` 의 `purge_artifacts` 는 `artifact_path`(= `<claude_dir>/<ws_key>/<uuid>.jsonl`) 하나만 지운다. - claude 어댑터는 `residual_artifacts` 를 재정의하지 않는다. 그래서 base 기본 구현(`lib_py/agents/base.py:189-192`, "the default has nothing to scan" → `[]`)이 쓰이고, 잔여물 유무와 무관하게 항상 빈 목록을 돌려준다. - 비교: agy 어댑터는 #10 에서 DB 사이드카(`-wal`/`-shm`/`-journal`)·`brain/<uuid>`·annotation·presence lock 까지 purge 하도록 고쳤고(`adapters/agy.py:98-128`), `residual_artifacts` 로 루트를 walk 해 같은 UUID 를 담은 경로를 보고한다(`adapters/agy.py:130-`). 현재 `residual_artifacts` 를 재정의한 어댑터는 agy 뿐이다. ## 영향 - `--purge-conversation` 은 "복구 불가"를 전제로 안내하지만, claude 대화는 세션 부속 데이터가 남는다. `file-history` 에는 그 세션이 다룬 파일 내용 일부가 들어 있다. - 보고가 `residual: none` 이라 사용자가 남은 항목을 인지할 수 없다. 이는 #10 이 agy 에서 고친 것과 같은 계열의 빈틈이다. ## 제안 1. claude 어댑터의 purge 대상에 `~/.claude/file-history/<uuid>/` 와 `~/.claude/session-env/<uuid>/` 를 추가한다(존재할 때만, 디렉터리 단위). 2. claude 어댑터에 `residual_artifacts` 를 재정의해 `~/.claude` 아래에서 UUID 를 포함하는 경로를 보고한다(agy 와 같은 방식, 범위는 `claude_dir` 상위로 한정). 3. 나머지 어댑터(codex·grok·opencode·hermes)도 각 CLI 의 세션 부속 파일 위치를 확인해 같은 계약으로 맞춘다. 4. 회귀 테스트: 임시 홈에 `<uuid>.jsonl`·`file-history/<uuid>/`·`session-env/<uuid>/` 를 만든 뒤 purge 하고, 세 경로가 모두 사라지며 residual 보고가 비는지 검증한다. ## 관련 - #10 agy 어댑터가 대화 부속 파일을 삭제하지 않던 문제(같은 계열) - #13 오케스트레이터 대화 purge 도입 ## 환경 정보 - main `1134d74`(v4.6.0) 기준, 작업 브랜치 `feat/issue-21-items-4-5-7` - Claude Code v2.1.270, Linux
Author
Owner

추가 관측 (2026-09-21) — creator 세션 2건 purge

작업이 끝난 creator 두 개를 stop_session.sh --purge-conversation --yes 로 정리하면서 이 이슈가 그대로 재현됐고, 별개의 문서-동작 불일치도 함께 확인했다.

1. 잔여물 (이 이슈 본문과 동일)

세션 uuid 스킬이 지운 것 남은 것
creator-claude-01 d0245411-… projects/<ws_key>/<uuid>.jsonl file-history/<uuid>/(1.18MB), session-env/<uuid>/
creator-claude-issue20 d93d5b41-… projects/<ws_key-wt>/<uuid>.jsonl file-history/<uuid>/(220KB), session-env/<uuid>/

두 경우 모두 스킬은 잔여물을 보고하지 않았고(residual 없음), 남은 항목은 수동으로 지웠다. file-history 에는 그 세션이 편집한 파일 내용이 들어 있다.

2. 문서-동작 불일치 (추가 지적)

--purge-conversation 이후 레지스트리 행이 남는다고 문서에 적혀 있으나, 구현은 행을 삭제한다.

  • 문서 (.agents/skills/multi-agent-mux-stop/SKILL.md)
    • :95 상태 전이표 — running ──(stop --purge-conversation --yes)► terminated (resumable:false, conv deleted)
    • :101 — "If --purge-conversation is used: status: terminated, terminated_at, terminated_at_epoch, termination_mode: purge and resumable: false."
    • :77 워크플로 주석 — "this prevents any future resume (status=terminated, resumable=false)"
  • 구현 (.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh:353)
    • removed: {name} (registry entry fully purged from YAML+DB)
    • 실제로 .mam/agent-sessions.yaml 의 행이 사라졌다(7행 → 5행). terminated 상태로 남은 행은 없다.

영향: 문서대로 status: terminated 행을 조회하는 후속 절차·코드는 빈 결과를 본다. purge 된 세션의 감사 흔적(정지 시각, 사유, pane 메타)도 레지스트리에 남지 않는다.

제안: 둘 중 하나로 계약을 맞춘다.

  1. 문서를 실제 동작에 맞춘다 — 행 삭제를 명시하고 상태 전이표에서 terminated 를 제거하거나 "행 제거"로 바꾼다.
  2. 구현을 문서에 맞춘다 — 행을 status: terminated, resumable: false 로 보존한다.

#17 항목 6(문서-코드 계약 검사)의 대상이기도 하다.

3. 참고 (이 이슈 범위 밖)

같은 실행에서 stop 이 행의 delegate_job_id 로 progress/completed 를 발행하려다 브로커 연결 거부([Errno 111])로 3회 재시도 후 실패했다. 정지·purge 자체는 성공했다. 브로커가 내려가 있던 환경 요인이다.

## 추가 관측 (2026-09-21) — creator 세션 2건 purge 작업이 끝난 creator 두 개를 `stop_session.sh --purge-conversation --yes` 로 정리하면서 이 이슈가 그대로 재현됐고, 별개의 문서-동작 불일치도 함께 확인했다. ### 1. 잔여물 (이 이슈 본문과 동일) | 세션 | uuid | 스킬이 지운 것 | 남은 것 | |---|---|---|---| | `creator-claude-01` | `d0245411-…` | `projects/<ws_key>/<uuid>.jsonl` | `file-history/<uuid>/`(1.18MB), `session-env/<uuid>/` | | `creator-claude-issue20` | `d93d5b41-…` | `projects/<ws_key-wt>/<uuid>.jsonl` | `file-history/<uuid>/`(220KB), `session-env/<uuid>/` | 두 경우 모두 스킬은 잔여물을 보고하지 않았고(`residual` 없음), 남은 항목은 수동으로 지웠다. `file-history` 에는 그 세션이 편집한 파일 내용이 들어 있다. ### 2. 문서-동작 불일치 (추가 지적) `--purge-conversation` 이후 **레지스트리 행이 남는다고 문서에 적혀 있으나, 구현은 행을 삭제한다.** - 문서 (`.agents/skills/multi-agent-mux-stop/SKILL.md`) - `:95` 상태 전이표 — `running ──(stop --purge-conversation --yes)► terminated (resumable:false, conv deleted)` - `:101` — "If `--purge-conversation` is used: `status: terminated`, `terminated_at`, `terminated_at_epoch`, `termination_mode: purge` and `resumable: false`." - `:77` 워크플로 주석 — "this prevents any future resume (status=terminated, resumable=false)" - 구현 (`.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh:353`) - `removed: {name} (registry entry fully purged from YAML+DB)` - 실제로 `.mam/agent-sessions.yaml` 의 행이 사라졌다(7행 → 5행). `terminated` 상태로 남은 행은 없다. 영향: 문서대로 `status: terminated` 행을 조회하는 후속 절차·코드는 빈 결과를 본다. purge 된 세션의 감사 흔적(정지 시각, 사유, pane 메타)도 레지스트리에 남지 않는다. 제안: 둘 중 하나로 계약을 맞춘다. 1. 문서를 실제 동작에 맞춘다 — 행 삭제를 명시하고 상태 전이표에서 `terminated` 를 제거하거나 "행 제거"로 바꾼다. 2. 구현을 문서에 맞춘다 — 행을 `status: terminated`, `resumable: false` 로 보존한다. #17 항목 6(문서-코드 계약 검사)의 대상이기도 하다. ### 3. 참고 (이 이슈 범위 밖) 같은 실행에서 stop 이 행의 `delegate_job_id` 로 `progress`/`completed` 를 발행하려다 브로커 연결 거부(`[Errno 111]`)로 3회 재시도 후 실패했다. 정지·purge 자체는 성공했다. 브로커가 내려가 있던 환경 요인이다.
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: tmpl/multi-agent-mux#31