- Remove dead agent_identities read path and PyYAML import from workspace_uuid.py - Defer eager PyYAML import in verify_session.py to lazy YAML fallback branch - Simplify UUID resolution to 2-tier model (tier-1 own row ID -> tier-2 adapter scan) - Clean up unused Drift D and ghost cache clearing in reconcile.sh and stop_session.sh - Add 3 regression guards in tests/test_tier1_unit.py (266/266 PASS) - Update IMPROVEMENTS.md, VERSIONS.md, and SKILL.md files
25 KiB
📐 구현 계획서 Rev.2 — B-10 (P3-2): agent_identities tier-3 신원 캐시 완전 제거 (Option A)
- Job ID:
104b94c8(Rev.1 =00334786) - Planner: claude (session:
herdr:canary-projects-multi-agent-mux-creator-claude) - Role: Planner (
MULTI_AGENT_RULES.md§1 — 본 작업에서 저장소 코드 0건 수정) - 반영 대상 Challenge:
26f5d224(agy, Worker / Plan Reviewer) —[VERDICT: PASS WITH CHALLENGE] - 기준 커밋:
7e21077(refactor, 작업 트리 clean)
0. 요약
Challenge 2건 모두 타당합니다. 전면 수용합니다. 격리 클론에서 Rev.1 의 가드 코드를 원문 그대로 실행해 두 결함을 재현했습니다.
그리고 챌린저의 권고안 #1 을 실제로 구현해 보는 과정에서 생산 코드 결함 1건을 새로 발견했습니다. 이것이 이번 Rev.2 의 가장 중요한 산출입니다.
신규 발견:
verify_session.py:10이import os, sys, json, sqlite3, yaml로 yaml 을 즉시 import 합니다. 이 함수(mam_orchestrator_uuids)는find_workspace_uuid_main()이:38에서 tier 로직보다 먼저 호출합니다. 따라서 tier-3 을 제거해도 UUID 해결 경로는 여전히 PyYAML 을 요구합니다. 브리프의 목표("remove PyYAML dependency from workspace_uuid.py")는 파일 단위로는 달성되지만 실행 경로 단위로는 달성되지 않습니다.
이는 B-10 항목 (b) 가 원래 lib.sh/load_state_json 에 대해 서술했던 바로 그 결함 패턴이 다른 파일에 미수정 상태로 남아 있던 것입니다. state.py:34 가 이미 올바른 선례(분기 내부 import)를 제공하므로 1줄로 교정됩니다. 단계 4 로 추가했습니다.
| 항목 | Rev.1 | Rev.2 |
|---|---|---|
C2 pathlib NameError |
존재 | 수정 |
| C1 가드 공허성 | import lib_py.workspace_uuid — 베이스라인에서도 통과 |
AST 검사 + 실행 검사 2종으로 교체 |
| 가드 수 | 2 | 3 |
verify_session.py:10 즉시 yaml import |
미인지 | 단계 4 신설 |
| 뮤테이션 검증 | 계획만 제시(M1~M3) | 5종 실측 완료(M1·M2·M3a·M3b·M4) |
| 제거 단계 자체의 실행 검증 | 미실시 | 클론에 선적용 후 구문·가드·전체 회귀 확인 |
1. Challenge 판정 — 2건 모두 수용 (실행으로 재현)
1.1 C2 — pathlib NameError (확인)
Rev.1 §5.1 의 두 번째 테스트는 지역 import 가 subprocess, sys, os 뿐인데 pathlib.Path 를 씁니다. 첫 번째 테스트가 pathlib 을 import 하지만 그것은 자기 함수 스코프이고, tests/test_tier1_unit.py:1-8 에도 최상위 import pathlib 이 없습니다(확인).
Rev.1 가드를 클론에 원문 그대로 붙여 실행:
> skills = str(pathlib.Path(__file__).resolve().parent.parent / ".agents" / "skills")
E NameError: name 'pathlib' is not defined
tests/test_tier1_unit.py:370: NameError
챌린저가 예측한 그 줄에서 정확히 재현되었습니다. 단순 누락이며 제 실수입니다.
1.2 C1 — 가드가 베이스라인에서 통과(공허) (확인)
pathlib 만 고치고 tier-3 이 그대로 살아 있는 미수정 베이스라인에서 다시 실행:
tests/test_tier1_unit.py::test_b10_no_agent_identities_reader_in_production FAILED ← 정상 (offender 9건 열거)
tests/test_tier1_unit.py::test_b10_workspace_uuid_needs_no_pyyaml PASSED ← 공허
1 failed, 1 passed
가드 1 은 제 역할을 합니다(제거 전이므로 실패). 가드 2 는 제거가 일어나지 않았는데도 통과합니다 — 챌린저 지적대로 import lib_py.workspace_uuid 는 find_workspace_uuid_main() 을 실행하지 않으므로 :100 의 지연 import 에 도달하지 못합니다.
추가 실측 — 공허성의 정확한 범위: Rev.1 이 제안했던 뮤테이션 M3(최상위 import yaml 추가)은 실제로는 잡습니다. 잡지 못하는 것은 이 저장소에 실제로 존재했던 형태, 즉 함수 내부 지연 import 입니다.
| 뮤테이션 | Rev.1 가드 2 |
|---|---|
M3a — 최상위 import yaml |
FAIL ✅ 잡음 |
M3b — 함수 내부 지연 import yaml (C1 이 지목한 형태) |
PASS ❌ 못 잡음 |
즉 제가 설계한 가드는 제가 상상한 결함 형태만 방어하고 실제로 있었던 형태는 놓칩니다. 챌린저 지적이 정확합니다.
2. 챌린저 권고안 평가
챌린저는 두 가지를 권고했습니다.
2.1 권고 #2 (AST/텍스트 검사) — 채택, AST 로 정밀화
텍스트 부분 문자열 검사("yaml" not in source)는 YAML_PATH 같은 정당한 식별자에 걸려 향후 오탐을 냅니다. AST 로 Import/ImportFrom 노드만 검사하면 중첩 깊이와 무관하게 정확히 잡습니다.
2.2 권고 #1 (mock env 로 find_workspace_uuid_main() 실행) — 채택, 단 그대로는 오탐
방향은 옳습니다. 그러나 명세된 형태로 구현하면 완벽한 B-10 구현 위에서도 실패합니다. 챌린저가 제시한 4개 환경변수(WS_ABS, AGENT, MAM_STATE_JSON, YAML_PATH)를 갖추고 noyaml 스텁 하에서 실행한 결과:
AssertionError: resolution path still needs PyYAML:
File ".../lib_py/workspace_uuid.py", line 38, in find_workspace_uuid_main
orchestrator_ids = set(mam_orchestrator_uuids())
File ".../lib_py/verify_session.py", line 10, in mam_orchestrator_uuids
ImportError: PyYAML absent (stub)
실패 원인은 workspace_uuid.py 가 아니라 verify_session.py 입니다 — §3 의 신규 발견으로 이어집니다. 권고 #1 은 그 결함을 함께 고친 뒤에야 의미 있는 가드가 됩니다. 이 계획은 둘 다 반영합니다.
3. 🆕 신규 발견 — verify_session.py:10 의 즉시 yaml import
3.1 결함
# verify_session.py:6-11
def mam_orchestrator_uuids():
global _MAM_ORC_CACHE
if _MAM_ORC_CACHE is not None:
return _MAM_ORC_CACHE
import os, sys, json, sqlite3, yaml # ← :10 yaml 을 무조건 import
override = os.environ.get("MAM_ORCHESTRATOR_UUIDS")
yaml 은 이 함수 안에서 실제로 쓰입니다 — :48 의 yaml.safe_load(f) (YAML 폴백). 문제는 import 위치입니다. :10 은 함수 진입 즉시 실행되므로:
- DB 분기만 타도 PyYAML 필요
MAM_ORCHESTRATOR_UUIDS환경변수로 조기 반환해도 필요 (import 가:10, 오버라이드 검사가:11)
실측 — 오버라이드를 빈 문자열로 주어 즉시 반환시켜도:
$ PYTHONPATH=<noyaml>:... MAM_ORCHESTRATOR_UUIDS="" python -c "…mam_orchestrator_uuids()"
ImportError: PyYAML absent (stub)
3.2 왜 B-10 범위인가
find_workspace_uuid_main() 은 :38 에서 mam_orchestrator_uuids() 를 호출합니다 — tier-1 보다도 먼저입니다. 따라서 tier-3 을 지워도 UUID 해결 경로 전체는 PyYAML 을 요구한 채 남습니다. 브리프의 목표를 실행 경로 기준으로 달성하려면 이 한 줄이 필요합니다.
또한 이것은 B-10 항목 (b) 가 서술한 것과 동일한 결함 패턴입니다. (b) 는 lib.sh/load_state_json 에 대해 제기되었고 state.py 이관 과정에서 해소되었는데(Rev.1 §1.2), 같은 패턴이 verify_session.py 에 남아 있었습니다. B-10 을 "PyYAML 의존 완화" 과제로 닫으면서 이걸 남기면 항목이 절반만 닫힙니다.
3.3 교정 — state.py:34 선례를 그대로 따름
import os, sys, json, sqlite3 # :10 — yaml 제거
...
if (d_obj is None or "orchestrator_uuids" not in d_obj) and os.path.exists(yaml_p):
try:
import yaml # ← YAML 폴백 분기 안으로
with open(yaml_p) as f:
d_obj = yaml.safe_load(f) or {}
실측 확인: 이 교정 후 §4 의 실행 가드가 통과합니다(교정 전 FAIL → 교정 후 PASS).
3.4 lib_py 의 yaml import 전수 조사
| 위치 | 판정 |
|---|---|
atomic_yaml.py:6 (모듈 최상단) |
정당 — 모듈의 존재 이유가 YAML 직렬화이고, 이중 인터프리터 전략상 시스템 python3(PyYAML 보유)에서만 실행됨 |
state.py:34 (분기 내부) |
이미 올바름 — 이번 교정의 선례 |
workspace_uuid.py:100 (tier-3 내부) |
B-10 단계 1 에서 제거 |
verify_session.py:10 (함수 즉시) |
단계 4 신설 |
교정 후 lib_py 의 무조건적 PyYAML 요구는 atomic_yaml.py 하나로 수렴합니다.
4. 확정 회귀 가드 — 3종, 뮤테이션 5종 실측 완료
4.1 확정 코드 — tests/test_tier1_unit.py 에 추가
def test_b10_no_agent_identities_reader_in_production():
"""B-10: agent_identities has no writer; no production code may read it."""
import pathlib
root = pathlib.Path(__file__).resolve().parent.parent
targets = [
root / ".agents" / "skills" / "lib_py" / "workspace_uuid.py",
root / ".agents" / "skills" / "multi-agent-mux-monitor" / "scripts" / "reconcile.sh",
root / ".agents" / "skills" / "multi-agent-mux-stop" / "scripts" / "stop_session.sh",
root / ".agents" / "skills" / "lib.sh",
]
offenders = []
for f in targets:
for i, line in enumerate(f.read_text().splitlines(), 1):
if "agent_identities" not in line:
continue
if line.lstrip().startswith("#"): # 금지 규약을 서술하는 주석은 허용
continue
offenders.append(f"{f.name}:{i}: {line.strip()}")
assert not offenders, "agent_identities read path resurrected:\n" + "\n".join(offenders)
def test_b10_workspace_uuid_has_no_yaml_import():
"""B-10: no `import yaml` anywhere in workspace_uuid.py — top-level OR lazy."""
import ast, pathlib
src = (pathlib.Path(__file__).resolve().parent.parent
/ ".agents" / "skills" / "lib_py" / "workspace_uuid.py")
tree = ast.parse(src.read_text())
offenders = []
for node in ast.walk(tree): # ast.walk → 중첩 깊이 무관
if isinstance(node, ast.Import):
for a in node.names:
if a.name.split(".")[0] == "yaml":
offenders.append(f"line {node.lineno}: import {a.name}")
elif isinstance(node, ast.ImportFrom):
if (node.module or "").split(".")[0] == "yaml":
offenders.append(f"line {node.lineno}: from {node.module} import ...")
assert not offenders, "PyYAML dependency reintroduced:\n" + "\n".join(offenders)
def test_b10_find_workspace_uuid_runs_without_pyyaml(tmp_path):
"""B-10: the executed resolution path must not need PyYAML."""
import subprocess, sys, os, json, pathlib
stub = tmp_path / "noyaml"
(stub / "yaml").mkdir(parents=True)
(stub / "yaml" / "__init__.py").write_text('raise ImportError("PyYAML absent (stub)")\n')
skills = str(pathlib.Path(__file__).resolve().parent.parent / ".agents" / "skills")
ws = tmp_path / "ws"; ws.mkdir()
env = os.environ.copy()
env["PYTHONPATH"] = f"{stub}:{skills}"
env["WS_ABS"] = str(ws)
env["AGENT"] = "claude"
env["MAM_STATE_JSON"] = json.dumps({"herdr_sessions": []})
env["YAML_PATH"] = str(tmp_path / "agent-sessions.yaml")
env["HOME_DIR"] = str(tmp_path)
env["CLAUDE_PROJECT_DIR"] = str(tmp_path / "projects")
r = subprocess.run(
[sys.executable, "-c",
"from lib_py.workspace_uuid import find_workspace_uuid_main; find_workspace_uuid_main()"],
capture_output=True, text=True, env=env)
assert r.returncode == 0, f"resolution path still needs PyYAML: {r.stderr}"
assert "yaml" not in r.stderr.lower(), f"PyYAML touched at runtime: {r.stderr}"
env 를 명시 구성하므로 앰비언트 PYTHONPATH 에 의존하지 않습니다(직전 라운드 N1 재발 방지). 지역 import 에 pathlib 을 포함시켜 C2 를 해소했습니다.
4.2 뮤테이션 매트릭스 — Rev.2 에서 실측
클론에 §5 단계 1~4 를 선적용한 뒤 측정했습니다.
| # | 뮤테이션 | 기대 | 실측 |
|---|---|---|---|
| — | baseline (제거 + 교정 적용) | PASS | 3 passed ✅ |
| M1 | workspace_uuid.py 에 agent_identities 읽기 복원 |
가드 1 FAIL | 1 failed ✅ |
| M2 | reconcile.sh 에 drift D 읽기 복원 |
가드 1 FAIL | 1 failed ✅ |
| M3a | 최상위 import yaml |
가드 2 FAIL | 2 failed ✅ (실행 가드도 동반 실패) |
| M3b | 함수 내부 지연 import yaml (C1 형태) |
가드 2 FAIL | 1 failed ✅ ← Rev.1 이 놓쳤던 형태 |
| M4 | verify_session.py yaml 지연 교정 되돌림 |
가드 3 FAIL | 1 failed ✅ |
M3b 가 Rev.2 의 핵심 개선입니다 — Rev.1 가드에서는 이 뮤테이션이 통과했습니다.
5. 구현 계획
5.1 단계 1 — workspace_uuid.py tier-3 제거
ai = d.get('agent_identities') … 부터 print('') 직전까지 28줄 삭제, import 를 import os, sys, json 으로 축소(sqlite3 은 tier-3 외 사용처 0건).
클론 실측: 삭제 후
ast.parseOK, 전체 회귀 §8-9 참조.
5.2 단계 2 — reconcile.sh drift D 제거
# === drift D: stale UUID … === 부터 result = { 직전까지 35줄 삭제. bash -n OK 확인.
주의: glob/sqlite3 import 는 다른 분기에서도 쓰이므로 제거하지 마십시오(클론 실측에서 삭제 없이 정상 동작).
5.3 단계 3 — stop_session.sh 캐시 소거 제거
# agent_identities 는 cache — … 블록 6줄 삭제. :164 주석을 tier-1(row) -> tier-2(workspace-scoped disk scan) 로 정정. bash -n OK 확인.
5.4 🆕 단계 4 — verify_session.py:10 yaml 지연화 (§3)
- import os, sys, json, sqlite3, yaml
+ import os, sys, json, sqlite3
그리고 yaml.safe_load 를 쓰는 YAML 폴백 try: 블록 첫 줄에 import yaml 을 삽입합니다. 1줄 이동이며 state.py:34 와 동일한 형태입니다.
5.5 단계 5 — lib.sh 주석 정정
# Resolution order:
# 1) herdr_sessions[] row whose pane.cwd == this workspace -> per-row own id
# (claude_session_id_own / agy_conversation_id_own)
# 2) on-disk scan scoped to this workspace, via the agent adapter's discover()
# Prints the UUID on stdout (empty line if none). Always exits 0.
:1326 의 3-tier → 2-tier, … -> cwd-matched cache 제거.
5.6 단계 6 — 스킬 문서
status/SKILL.md:108drift D 행 삭제 (A/B/C 3종만)monitor/SKILL.md:143예시 출력의agent_identities.*줄 삭제resume/SKILL.md:50-58해결 순서 교체 — 기존 서술이 이미 오류입니다.agent_identities를 1·2순위 primary 로 안내하고 있으나 P0-C 가 이를 cache 로 강등했습니다(update_yaml_resumed.sh:5가 명시). 실제 순서로 교체:
1. herdr_sessions[] 행의 per-row own id (claude_session_id_own / agy_conversation_id_own)
— multi-agent-mux-stop 이 종료 직전 확정 기록한 값 (tier-1, race-free)
2. 워크스페이스로 스코프된 온디스크 스캔 (어댑터 discover())
둘 다 비면 → 이 워크스페이스에는 아직 대화가 없음. multi-agent-mux-create 로.
보존: resolve_session_id.sh:7 의 # P0-C: 전역 agent_identities 를 즉시 반환하지 않는다 는 금지 규약 서술이므로 유지합니다(tier-3 제거로 오히려 더 정확해짐). 가드 1 의 주석 허용 규칙이 이를 통과시킵니다.
6. adapter.identity_cache_fields — Option A 확정
Rev.1 §4 에서 판단을 요청했고 챌린저가 §3 표에서 "Adopt Option A" 로 동의했으므로 확정합니다.
단계 3 이 stop_session.sh 의 유일한 생산 소비자를 제거하므로, base.py:57 에 근거 주석을 반드시 남깁니다.
@property
def identity_cache_fields(self) -> tuple:
"""agent_identities 캐시의 에이전트별 필드명.
B-10(Option A)로 캐시 읽기 경로가 제거되어 현재 생산 소비자는 0건이지만,
캐시 쓰기 경로가 도입되면 즉시 필요한 유일한 스키마 기술이므로 존치한다.
임의 삭제 금지 — 삭제 시 4개 어댑터에 필드명을 다시 흩뿌려야 한다."""
raise NotImplementedError
근거 없는 미사용 속성은 다음 정리 라운드에서 "쉬운 삭제 대상"으로 오인됩니다 — C-4 가 _HERDR_SHIM_DIR_PATTERN 에서 정확히 그 사례였습니다.
7. 문서 동기화
7.1 IMPROVEMENTS.md — 7곳
| 행 | 현재 | 변경 후 |
|---|---|---|
:3 |
최종 갱신일 2026-08-17 (…, C-6 완료, 263/263) |
B-10 완료 및 266/266 반영 |
:5 |
미해결 4건 (아키 1, 엣지 3, 오케 0, 레거시 0) | 미해결 3건 (아키 1, 엣지 2, 오케 0, 레거시 0) |
:6 |
완료 21건 | 완료 22건, 목록에 B-10 추가 |
:70 |
## 2. … (Edge-case Bugs — 3건) |
… (Edge-case Bugs — 2건) |
:79-80 |
B-10 항목 | 삭제 (§5 로 이동) |
:92 |
## 5. … (Completed Tasks — 21건) |
… (Completed Tasks — 22건) |
:241 |
| **P3-2** | **B-10** | tier-3 신원 캐시 존치/제거 결정 + PyYAML 의존 완화 | 중 | A-4 M2 | |
… tier-3 신원 캐시 완전 제거 (Option A) **(✅ 완료 — 전체 266/266 PASS)** | |
§5 신규 항목:
### **B-10 (P3-2): `agent_identities` tier-3 신원 캐시 완전 제거 (Option A)** — ✅ 완료
- 저장소 전체에 `agent_identities` 쓰기 코드가 0건임을 재확인하고(라이브 `.db` 최상위 키에도 부재),
구조적으로 히트 불가였던 읽기 경로 3곳을 제거했습니다 — `workspace_uuid.py` tier-3 폴백(28줄),
`reconcile.sh` drift D 진단(35줄), `stop_session.sh` purge 시 캐시 소거(6줄), 관련 주석 3곳.
UUID 해결은 tier-1(per-row own id) → tier-2(어댑터 `discover()`) 2단계로 단순화되었습니다.
- **PyYAML 의존 — 실행 경로 기준으로 해소**: `verify_session.py::mam_orchestrator_uuids` 가
`yaml` 을 함수 진입 즉시 import 하고 있어(`:10`), tier-3 을 지워도 UUID 해결 경로는 PyYAML 을
요구했습니다. `state.py` 의 기존 선례대로 YAML 폴백 분기 안으로 이동시켜 교정했습니다.
- **정정**: 원 항목이 서술했던 "`lib.sh` 의 PyYAML 하드 의존" 은 `load_state_json` 이 `state.py` 로
이관되며 **이미 해소된 상태**였습니다. 한편 `atomic_yaml.py` 는 모듈 존재 이유상 앞으로도
최상단에서 import 하므로 **저장소 차원의 PyYAML 요구와 설치 게이트는 유지**됩니다.
- 회귀 가드 3종을 신설하고 뮤테이션 5종(M1·M2·M3a·M3b·M4)으로 방어력을 검증했습니다.
주의: :5 의 엣지케이스 카운트와 :70 §2 헤더는 반드시 함께 바꿉니다.
7.2 VERSIONS.md
### 🚀 v2.0.0 changelog 에 #### 7 추가:
#### 7. `agent_identities` tier-3 신원 캐시 완전 제거 및 UUID 해결 경로 PyYAML 탈의존 (B-10 / Option A)
- 쓰기 경로가 존재하지 않아 구조적으로 히트 불가였던 tier-3 폴백과 부속 소비자
(`workspace_uuid.py`, `reconcile.sh` drift D, `stop_session.sh` 캐시 소거)를 전면 삭제.
- UUID 해결 경로를 **tier-1(per-row own id) → tier-2(어댑터 `discover()`)** 2단계로 단순화.
- `verify_session.py::mam_orchestrator_uuids` 의 즉시 `yaml` import 를 YAML 폴백 분기로 이동,
UUID 해결 경로가 PyYAML 없이 완주함을 실행 가드로 고정
(`atomic_yaml.py` 의 시스템 PyYAML 요구는 설계상 유지).
- 회귀 가드 3종 신설 — 읽기 경로 부활 차단, `import yaml` AST 검사(지연 import 포함), 실행 경로 검증.
:44 의 A-4 인터페이스 나열에서 identity_cache_fields 는 §6 Option A 에 따라 유지합니다.
8. 검증 절차
| # | 명령 / 확인 | 기대 |
|---|---|---|
| 1 | bash -n — lib.sh, reconcile.sh, stop_session.sh |
3/3 OK (클론 실측 완료) |
| 2 | python -c "import ast; ast.parse(open('workspace_uuid.py').read())" |
OK (클론 실측 완료) |
| 3 | grep -rn "agent_identities" .agents/skills/ |
주석 외 0건 |
| 4 | grep -rn "tier-3|3-tier" .agents/skills/ |
0건 |
| 5 | grep -n sqlite3 lib_py/workspace_uuid.py |
0건 |
| 6 | grep -n "yaml" lib_py/verify_session.py |
폴백 분기 내부 1건만 |
| 7 | 라이브 워크스페이스에서 find_workspace_uuid <ws> claude |
변경 전과 동일 출력 |
| 8 | reconcile.sh 1회 실행 후 drifts 클래스 집합 |
D 미출현, A/B/C 정상 |
| 9 | 뮤테이션 M1·M2·M3a·M3b·M4 | 각각 해당 가드 FAIL (§4.2 재현) |
| 10 | pytest tests/ -q |
266 passed (263 실측 + 가드 3건) |
| 11 | env -u PYTHONPATH pytest tests/test_tier1_unit.py -q |
전부 통과 (환경 비의존) |
| 12 | IMPROVEMENTS.md :5 ↔ :70 대조 |
엣지 카운트 일치 |
| 13 | IMPROVEMENTS.md :6 ↔ :92 대조 |
둘 다 22건 |
7번이 동작 동일성 핵심 검증입니다 — tier-3 이 히트 불가였다는 주장이 맞다면 출력이 바뀌어서는 안 됩니다.
10번은 약 6분 30초 소요됩니다. 백그라운드 실행 권장.
9. 규모 및 리스크
| 파일 | 변경 |
|---|---|
lib_py/workspace_uuid.py |
−28줄, sqlite3 import 제거 |
lib_py/verify_session.py |
🆕 yaml import 1줄 이동 |
reconcile.sh |
−35줄 (import 는 보존) |
stop_session.sh |
−6줄 + 주석 1곳 |
lib.sh |
주석 2곳 |
base.py |
identity_cache_fields 근거 docstring |
| SKILL.md 3종 | drift D 행·예시 1줄·해결 순서 |
IMPROVEMENTS.md / VERSIONS.md |
카운트·항목 이동 + changelog |
tests/test_tier1_unit.py |
가드 3건 |
| 테스트 총계 | 263 (실측) → 266 |
| 리스크 | 평가 |
|---|---|
| 동작 회귀 | 낮음. 제거 대상 전부 생산자 0인 데이터를 읽습니다. 클론 전체 회귀로 확인(§10) |
| 단계 4 부작용 | 낮음. import 위치만 이동하며 yaml 사용 지점은 그대로. state.py 에 동일 선례 존재 |
| 레거시 상태 파일 | ⚠️ 구버전 agent_identities 가 남은 .db/.yaml 이 있어도 tier-1·tier-2 가 동일 UUID 를 찾습니다. tier-3 은 앞 두 단계가 모두 실패해야 도달하던 경로이고, 스키마를 지우는 게 아니라 읽기를 멈추는 것이므로 데이터 파괴 없음 |
| drift D 진단 상실 | 영향 없음. 생산자 0이므로 한 번도 발화한 적 없음 |
identity_cache_fields 고아화 |
§6 Option A + 근거 docstring 으로 차단 |
| 가드 무력화 | §4.2 뮤테이션 5종으로 차단 |
권장 커밋 분할
refactor(uuid): drop the dead agent_identities tier-3 fallback (B-10)— 단계 1~3fix(verify): defer the yaml import so UUID resolution runs without PyYAML (B-10)— 단계 4test(b10): guard the read path, the yaml import, and the executed resolution path— §4docs: sync comments, SKILL.md resolution order, IMPROVEMENTS.md and VERSIONS.md for B-10— 단계 5~6 + §7
3번을 1·2번 뒤에 두면 가드가 앞 커밋 없이 실패하고 함께는 통과함을 커밋 순서로 증명할 수 있습니다. 2번을 분리하는 이유는 이것이 읽기 경로 제거와 독립된 생산 코드 수정이기 때문입니다 — 되돌릴 일이 생기면 따로 되돌릴 수 있어야 합니다.
10. 한계
- 본 계획은 Planner 산출물이며 저장소 파일을 수정하지 않았습니다(작업 트리 계획 전후 clean). 모든 실측은 격리 클론(
git clone --local --no-hardlinks)에서 수행했고 클론은 삭제했습니다. - 단계 1
4 를 클론에 선적용해 구문 검사·가드·뮤테이션·전체 회귀를 실측했습니다. 단계 56(주석·문서)은 실행 대상이 아니므로 적용하지 않았습니다. - 클론 전체 회귀 실측 완료: 단계 1~4 + 가드 3종을 적용한 클론에서 266 passed in 408.18s (0:06:48) — 기준 베이스라인
7e21077의 263 passed in 408.21s 대비 정확히 가드 3건 순증, 회귀 0건입니다. 즉 §8-10 의 266 목표치는 예측이 아니라 실측값입니다. 다만 이는 클론 측정이므로 구현 후 저장소에서 재확인하십시오. - 제안 가드 3종의 함수 수가 3이므로 266 을 목표치로 잡았습니다. 구현 시 함수를 병합하면 수치를 그에 맞춰 조정하십시오.
- 사용자 환경의 레거시
.db/.yaml에 실제로agent_identities가 남아 있는지는 이 워크스페이스 한 곳만 확인했습니다(부재). verify_session.py의yaml지연화는mam_orchestrator_uuids한 함수만 대상으로 했습니다. 같은 파일의 다른 함수는 감사하지 않았습니다(grep상yaml참조는 이 함수에만 존재).