OpenClaw·Hermes 마이그레이션 (2/13) — 1년 자산 중 무엇을 살리고 버릴까
다수의 운영 스크립트를 코드 리뷰하고 보존 / 부분 보존 / 폐기로 분류한 기록
이 글이 전달하는 것
- 레거시 에이전트 시스템을 후속 시스템으로 옮길 때 쓸 수 있는 자산 분류 기준 (보존/부분 보존/폐기 3단계)
- Strangler Fig + Subset Migration 전략을 메모리 파이프라인에 적용한 구체 사례
- 다수의 스크립트를 LOC·외부 의존성·대체 가능성 축으로 판정한 결과
- 비대해진 단일 파일(1310 LOC)을 마이그레이션 기회에 슬림화하는 방법
문제 정의: 전부 옮길까, 버릴까
오픈클로 인벤토리는 다수의 에이전트, 다수의 스케줄러 / 데몬, 다수의 운영 스크립트로 구성되어 있다. 후속 시스템인 헤르메스로 이관할 때 선택지는 둘 중 하나가 아니다. 전부 이식하면 누적 부채가 따라오고, 최소만 이식하면 축적된 도메인 로직을 버린다. 코드 리뷰 기반 자산 분류가 이 간극을 해결한다.
결정 컨텍스트 — 분류 기준을 만드는 5개 골조
자산을 분류하기 전에 이관 대상 아키텍처가 고정되어 있어야 한다. 분류 기준은 "이 코드가 목적지 구조에 들어갈 수 있는가"에서 도출되기 때문이다.
- 전략: Strangler Fig(점진 교체) + Subset Migration(부분 이식)
- 메모리: SQLite + Python 라이브러리(memcore). 데몬 없음. 별도 프로세스가 아니라 라이브러리로 import해서 쓰는 구조
- 폴더:
~/Hermes/로 분리.~/Project/의 오픈클로는 read-only 백업으로 보존 - 에이전트: '헤르메스 관리' 신규 생성. '오픈클로 관리'는 백업 전담으로 강등
- 컷오버: 듀얼 실행(같은 기능을 양쪽에서 돌리며 비교) → 검증 통과 후 컷오버
이 5개가 정해지면 분류 기준이 자동으로 파생된다. "memcore 라이브러리에 흡수 가능한가? Hermes profile에 녹일 수 있는가? 대체재가 이미 있는가?"
보존 (이식 필수)
| 파일 | LOC | 이식 형태 | 가치 |
|---|---|---|---|
| user-pattern-stage.py | 260 | memcore.dialectic 모듈 |
최고. U-tag 3-phase(관찰→가설→검증), Honcho 영감, anti-bias guard |
| confidence-decay.py | 82 | memcore cron tick | opinions confidence 0.02 감쇠, <0.30 제거 |
| topics-validate.py | 131 | memcore 정합성 체크 | bank ↔ topics 일관성 |
| topics-expand.py | 186 | memcore 자동 등록 | 신규 파일 자동 등록 |
| bank-lint.py | 176 | memcore validator | Retain 태그 포맷 검증, 데이터 무결성 |
| entity-audit.py | 152 | memcore stale 감지 | 30일 stale, SQLite timestamp 쿼리로 동등 |
| docs-snapshot.sh | 141 | Hermes cron payload | docs 변경 감지, URL만 변경 |
| release-check.sh | 66 | Hermes cron payload | 버전 변경 감지 |
판정 원리
보존 판정의 핵심 축은 외부 의존성 부재다. 보존 대상 전부 표준 라이브러리만 사용하고, 파일 I/O는 lib_common.py를 경유한다. 이관 작업은 lib_common.py를 memcore.io로 치환하는 단일 조작으로 귀결된다. 평균 175 LOC, 단위 테스트로 동등성 검증이 가능한 크기다.
최우선 자산: user-pattern-stage.py
이 파일은 사용자 발화 패턴을 관찰→가설→검증의 3단계 변증법으로 추적해 확증편향을 차단하는 로직을 구현한다. 후속 시스템(Hermes)에 동등 기능이 존재하지 않는다. 이 한 파일의 이관 여부가 마이그레이션의 정당성 지분 중 상당 부분을 차지한다.
부분 보존
| 파일 | LOC | 처리 |
|---|---|---|
| bank-size-watch.py | 176 | SQLite 전환 후 의미 약화. MemTree split 로직 일부만 |
| proactive-exception-alerts.py | 1310 | 과비대. 11개 escalation reason 판정 로직만 추출(~300 LOC), 알림 라우팅과 컨텍스트 수집은 Hermes gateway/hook에 위임 |
비대 파일 슬림화 패턴
proactive-exception-alerts.py는 1310 LOC로 누적 부채가 가장 큰 파일이다. 구조를 해부하면 세 층으로 나뉜다.
- 판정 로직 (~300 LOC): 11개 escalation reason을 평가하는 핵심 — 이관 대상
- 알림 라우팅: Hermes gateway로 위임 가능
- 컨텍스트 수집: Hermes hook 인프라로 위임 가능
마이그레이션은 이런 비대 파일을 슬림화할 자연스러운 진입점을 제공한다. 1310 → 300 LOC 축소는 기능 손실 없는 부채 정리다. 2, 3번 레이어는 목적지 인프라에 동등 기능이 있으므로 재작성 비용이 0에 가깝다.
폐기
| 파일 | LOC | 대체 |
|---|---|---|
| heartbeat-tick.py | 262 | Hermes cron + on_turn_start hook으로 100% 대체 |
heartbeat-tick.py는 목적지 인프라(cron + on_turn_start hook)가 동등 기능을 기본 제공한다. 이관 가치 없음. 폐기는 물리 삭제가 아니라 read-only 백업(~/Project/)으로의 격리를 의미한다. 참조 필요 시 언제든 열람 가능한 상태로 남긴다.
코드 리뷰 체크리스트 (재사용 가능)
자산 분류 시 각 파일에 다음 질문을 순서대로 던지면 판정이 수렴한다.
- 목적지에 동등 기능이 있는가? — 있으면 폐기 후보
- 외부 의존성이 있는가? — 없으면 이식 비용 낮음 → 보존 가능
- 파일 크기가 책임과 맞는가? — 과비대하면 부분 보존(슬림화)
- 고유 도메인 로직이 있는가? — 있고 재구현 비용이 크면 최우선 보존
- 테스트로 동등성 검증이 가능한가? — 가능해야 듀얼 실행 컷오버 성립
정리된 원리 4가지
- 이식 난이도는 LOC보다 의존성 그래프에서 결정된다. 평균 175 LOC 규모의 보존 자산들이 빠르게 이관 가능한 이유는
lib_common.py외 외부 의존이 없기 때문이다. - 작업량은 이식이 아니라 검증에서 발생한다. 코드 이관 자체는 1~2일 규모, 듀얼 실행 검증이 더 오래 걸린다.
- 고유 도메인 로직은 LOC 대비 가치가 비선형적이다. user-pattern-stage.py는 260 LOC지만 대체재 부재로 최우선 자산이 된다.
- 마이그레이션은 부채 정리의 자연 기회다. 과비대 파일(1310 LOC)의 슬림화는 별도 리팩터링 프로젝트보다 마이그레이션 컨텍스트에서 수행할 때 비용이 낮다.
적용 가능 범위와 열린 질문
이 분류 기법은 "레거시 시스템 → 후속 시스템"의 메모리/파이프라인 계층에 적용하기 쉽다. UI 계층이나 데이터 스키마 계층에는 동일 기준이 그대로 통하지 않는다. 외부 의존성 축 대신 스키마 호환성, 데이터 볼륨, 마이그레이션 다운타임이 더 지배적인 변수가 된다.
열린 질문:
- 보존 판정이 내려진 자산들이 duel-run 검증에서 실제로 동등성을 보이는가 — 아직 데이터로 확인되지 않은 가정이다.
- 부분 보존 사례의 슬림화 비율(1310 → 300)이 다른 파일에도 재현 가능한 패턴인지, 아니면 proactive-exception-alerts.py의 특이 구조 때문인지 분리 필요.
시리즈 전체 안내: 시리즈 목차
댓글
댓글 쓰기