22 KiB
📐 구현 계획서 Rev.2 — .env → .mam.env 마이그레이션 최종화 (Finalize)
- Job ID:
fe4e0e6f - Role: Planner
- 목표:
CURRENT_JOB.md기반 마이그레이션 최종화 · 원자적 커밋 · 리뷰어 검증 통과 - 선행 산출물:
78e83796(Rev.1) →6dc9d528(Rev.2) →4e8b4839(리뷰[VERDICT: NOT PASS]) →1b40c4ee(최종화 계획 Rev.1) → 본 문서 (Rev.2) - 반영 피드백: Creator
agyChallenge Report — Jobc6c43df9
0. 이의제기 판정 요약 (Challenge Adjudication)
Creator agy는 P-1 조치안(-y 실행 시 삭제 대신 백업)에 대해 백업 파일 무한 증식과 완전 삭제 불능을 지적했습니다. 실제 시나리오를 3주기 재현하여 검증했습니다.
| 항목 | 판정 | 근거 |
|---|---|---|
| 진단 — 반복 주기마다 백업 누적 | ✅ 채택 | 3주기 → 백업 3개 생성. 실측 확인 |
| 진단 — 백업 잔재를 타 도구가 오참조 | ❌ 기각 | *.mam-backup을 읽는 코드는 전무. remove.sh가 쓰기만 함. 전부 .gitignore 적용됨 |
진단 — -y로 완전 삭제 불가 |
⚠️ 부분 채택 | 사실이나 --purge-env가 이미 그 역할. 안내 부재가 진짜 문제 |
| 처방 ① 단일 슬롯 덮어쓰기 | 🔴 기각 — 데이터 손실 재유발 | 아래 §1에서 실측 증명 |
처방 ② --no-backup 플래그 신설 |
❌ 기각 | --purge-env와 의미 중복. 플래그 2개가 같은 일을 하면 P-1의 "권한 붕괴"가 재발 |
| 처방 ② 안내 문구 강화 | ✅ 채택 | stdout 가이드 추가 |
결론: agy의 문제 제기는 타당하나 처방은 위험합니다. 진단을 채택하되 처방은 교체합니다. 대안으로 **내용 기반 중복 제거(content dedup) + 최초 백업 불변(immutable slot 1)**을 제시합니다.
1. 🔴 agy 처방 ①(단일 슬롯 덮어쓰기)을 기각하는 이유 — 실측
remove.sh -y → install.sh 주기를 3회 반복하며 각 백업의 내용을 측정했습니다. (P-1 패치를 적용한 사본으로 실행. 리포지토리 코드는 미수정.)
CYCLE 0: 사용자 실제 설정 저장 → .mam.env = MQTT_PASSWORD=REAL_USER_SECRET
CYCLE 1: remove.sh -y → backups: .mam.env.mam-backup
reinstall → .mam.env 재생성됨 (설치기 기본값)
CYCLE 2: remove.sh -y → backups: .mam.env.mam-backup .mam.env.mam-backup.20260804173654
CYCLE 3: remove.sh -y → backups: … + .mam.env.mam-backup.20260804173658
핵심 측정 — 각 백업의 내용:
[.mam.env.mam-backup] -> REAL_USER_SECRET 1건 ← 사용자 실제 설정
[.mam.env.mam-backup.20260804173654] -> REAL_USER_SECRET 0건 ← 설치기 생성 기본값
[.mam.env.mam-backup.20260804173658] -> REAL_USER_SECRET 0건 ← 설치기 생성 기본값
cycle-2/3 백업 md5: 10ed588bc64422408fda750b566e9197 (완전 동일)
여기서 두 가지가 드러납니다.
(1) 증식의 실체는 "무가치한 사본의 반복"입니다.
사용자의 진짜 설정은 오직 슬롯 1에만 있습니다. 2주기 이후 백업은 install.sh가 방금 만든 기본 설정을 되받아 적은 것이며, 서로 바이트 단위로 동일합니다. 즉 증식은 "정보가 늘어나는 것"이 아니라 같은 쓰레기가 늘어나는 것입니다. → 내용 기반 중복 제거로 완전히 해결 가능합니다.
(2) 단일 슬롯 덮어쓰기는 그 유일한 진짜 설정을 파괴합니다.
agy의 처방 ①을 실제로 적용해 보았습니다:
BEFORE — 슬롯 1의 REAL_USER_SECRET 보유: 1건
현재 live .mam.env 의 보유: 0건 (설치기 기본값)
$ mv -f .mam.env .mam.env.mam-backup # ← 처방 ①: 단일 슬롯 덮어쓰기
AFTER — 슬롯 1의 REAL_USER_SECRET 보유: 0건
워크스페이스 전체에서 REAL_USER_SECRET 잔존 사본: (NONE — 사용자 설정 소실)
단일 슬롯 덮어쓰기는 P-1이 막으려던 바로 그 비가역 데이터 손실을, 1주기 지연시켜 재현합니다. 원래 P-1은 "즉시 삭제"였고 처방 ①은 "다음 주기에 삭제"입니다. 손실 시점만 다를 뿐 결과는 동일하며, 오히려 "백업했다"는 로그가 남아 있어 더 탐지하기 어렵습니다.
역설적으로, 현재 코드의 타임스탬프 폴백(remove.sh:182-184)은 바로 이 사고를 막고 있던 안전장치였습니다. 이것을 제거해서는 안 됩니다.
기각 사유 요약: 디스크 정리(위생 문제)를 위해 데이터 보존(정확성 문제)을 희생하는 교환입니다. 우선순위가 역전되어 있습니다.
2. ✅ P-1 조치안 개정 (Revised Remedy)
2-1. 삭제 권한 분리 — Rev.1과 동일 (변경 없음)
should_delete_env=0
if [ $PURGE_ENV -eq 1 ]; then
should_delete_env=1
elif [ $env_created_by_mam -eq 1 ] && [ $FORCE -eq 0 ]; then
if ! read -p "❓ MAM-created '$env_name' found. Delete it? (Saying No preserves it) [y/N]: " -r env_response; then
env_response="n"
fi
if [[ "$env_response" =~ ^[yY](es)?$ ]]; then
should_delete_env=1
fi
fi
2-2. 🆕 백업 정책 개정 — 내용 기반 중복 제거 + 슬롯 1 불변
agy가 제기한 증식 문제를 데이터 손실 없이 해소합니다.
# 원칙: 기존 백업은 절대 덮어쓰지 않는다.
# 동일 내용이 이미 보존돼 있으면 새 사본을 만들지 않는다.
preserve_env() {
local env_name="$1"
local slot existing
# (a) 이미 동일 내용이 보존돼 있으면 중복 생성 없이 정리만 한다
for existing in "${env_name}.mam-backup" "${env_name}".mam-backup.*; do
[ -f "$existing" ] || continue
if cmp -s "$env_name" "$existing"; then
rm -f "$env_name"
echo "ℹ️ '$env_name' is already preserved in $existing (no duplicate created)."
return 0
fi
done
# (b) 내용이 다르면 새 슬롯에 보존한다. 슬롯 1은 영구 불변.
slot="${env_name}.mam-backup"
if [ -e "$slot" ]; then
slot="${env_name}.mam-backup.$(date +%Y%m%d%H%M%S)"
# 동일 초 내 재실행 충돌 방지
local n=1
while [ -e "$slot" ]; do
slot="${env_name}.mam-backup.$(date +%Y%m%d%H%M%S)-$n"
n=$((n + 1))
done
fi
mv "$env_name" "$slot"
echo "💾 Backed up $env_name -> $slot"
echo " To remove the configuration entirely, re-run with --purge-env."
}
효과 (측정 기반 예측):
| 시나리오 | Rev.1 계획 | Rev.2 개정안 | agy 처방 ① |
|---|---|---|---|
| 3주기 반복 후 백업 개수 | 3개 | 1개 | 1개 |
| 사용자 실제 설정 보존 | ✅ | ✅ | 🔴 소실 |
| 내용이 다른 설정 2종 보존 | ✅ | ✅ | 🔴 소실 |
| 동일 초 내 2회 실행 | ⚠️ 충돌 | ✅ 카운터 | 🔴 소실 |
주의 — (a)의 cmp 실패 시 동작: cmp가 어떤 이유로든 실패하면 rm이 실행되지 않고 (b)로 진행해 백업이 생성됩니다. 즉 판단 불능 시 보존 쪽으로 실패(fail-safe) 합니다. 이 방향성을 반드시 유지해야 합니다.
2-3. 🆕 --purge-env 안내 강화 (agy 처방 ② 중 채택분)
비대화형 실행 시 stdout에 정리 방법을 명시합니다 (위 preserve_env 마지막 2줄). --no-backup은 신설하지 않습니다 — --purge-env와 기능이 동일하며, 같은 의미의 플래그를 2개 두는 것이 애초 P-1(-y와 --purge-env의 권한 붕괴)의 원인이었습니다.
2-4. 📌 근본 해법은 별건 (범위 외 · 후속 과제로 등재)
증식의 진짜 원인은 백업 정책이 아니라, 백업이 바로 옆에 있는데도 install.sh가 기본 설정을 새로 생성한다는 점입니다(M-1 가드가 *.mam-backup을 고려하지 않음). install.sh가 백업을 감지해 복원하도록 하면 증식은 발생 자체가 사라지고 재설치 UX도 개선됩니다.
다만 이는 설치기 동작 변경으로 별도 설계·검증이 필요하므로 본 마이그레이션 범위에서 제외하고 후속 과제(FU-1) 로 등재합니다. 2-2의 dedup만으로 agy가 제기한 증식은 실측상 해소됩니다.
3. 선행 리뷰 7개 항목 — 검증 결과 (변경 없음)
실제 명령 실행으로 확인한 현재 워킹 트리 상태 기준입니다.
| # | 리뷰(4e8b4839) 지적 |
상태 | 근거 |
|---|---|---|---|
| 1 | remove.sh:192 고아 fi |
✅ 해결 | deploy/*.sh 5개 전부 bash -n 통과 |
| 2 | T-8/T-10/T-11/T-12 미구현 | ⚠️ 부분 | T-8·10·12·13 추가. T-11·14·15 없음 |
| 3 | T-4 무력 테스트 | ✅ 해결 | patch.object(__file__) 후 인자 없이 호출 — 실제 경계 탐색 진입 |
| 4 | 문서 13개소 | ⚠️ 거의 | BOOTSTRAP 2개 .gitignore 예시만 잔존 (P-6) |
| 5 | 매니페스트 소유권 재기록 | ✅ 해결 | install.sh:288-305 |
| 6 | 래퍼 cwd 폴백 | ✅ 해결 | REPO_ROOT 우선 + 단계별 경고 |
| 7 | .tmp 잔여물 |
✅ 해결 | 없음 |
CURRENT_JOB.md의 파급 범위 오기: :23은 lib.sh에 ".env 로딩 로직"이 있다고 기술하나 사실이 아닙니다. lib.sh의 .env 매칭 27건은 전부 os.environ 부분 문자열, dotenv 참조는 0건. lib.sh는 범위 제외이며 이 오기를 근거로 수정하면 불필요한 회귀 위험만 발생합니다.
4. 🔴 머지 차단 결함 (Merge Blockers)
P-1 — --force가 사용자 설정을 백업 없이 삭제 (조치안은 §2로 개정)
재현:
printf '.env\nremove.sh\n' > .mam/install_manifest.txt
printf 'SECRET_KEY=user_secret_data\n' > .env
bash remove.sh --force
# EXITCODE=0 / 남은 파일: (없음) / .env.mam-backup 미생성 → 비가역 소실
근본 원인: 인자 파서(remove.sh:17-20)가 -y|--yes|--force를 하나의 FORCE로 묶고, 섹션 5가 FORCE=1을 삭제 권한으로 해석합니다. 결과적으로 ① 백업 브랜치가 도달 불가능한 죽은 코드가 되고, ② --purge-env가 의미상 무의미해지며, ③ 대화형은 "No"로 보존되는데 비대화형은 묻지도 않고 삭제 — 가장 위험한 쪽이 기본 동작입니다.
영향 범위: update.sh 경로는 안전합니다(:86,91이 remove.sh --force 호출 :151 이전에 *.update-tmp로 이동 → 섹션 5의 [ -f "$env_name" ] || continue에 걸림). 피해자는 remove.sh -y를 직접 실행하는 사용자/CI로 한정됩니다. 한정되지만 비가역입니다.
P-2 — T-8 단언문이 데이터 손실을 통과 판정
tests/test_env_migration.py:134:
self.assertTrue(os.path.exists(".env.mam-backup") or not os.path.exists(".env"))
or not os.path.exists(".env") 때문에 .env가 삭제되기만 하면 무조건 통과합니다. 막아야 할 실패 양상이 곧 통과 조건이 되는 논리 역전이며, P-1이 지금까지 발견되지 않은 직접적 원인입니다.
조치 — 보존 검증과 삭제 검증을 분리하고, §2-2 개정에 맞춰 케이스를 확장합니다.
def test_t8_remove_force_preserves_owned_env(self):
"""T-8 [BLOCKER]: --force must BACK UP owned env, never delete it."""
res = subprocess.run(["bash", "remove.sh", "--force"], capture_output=True, text=True)
self.assertEqual(res.returncode, 0, f"remove.sh failed: {res.stderr}")
self.assertTrue(os.path.exists(".env.mam-backup"),
"MAM-owned .env MUST be backed up under --force, never deleted")
with open(".env.mam-backup") as f:
self.assertIn("user_secret_data", f.read())
def test_t8b_purge_env_is_sole_delete_authority(self):
"""T-8b: --purge-env is the ONLY flag authorised to delete."""
subprocess.run(["bash", "remove.sh", "--force", "--purge-env"], check=True)
self.assertFalse(os.path.exists(".env"))
self.assertFalse(os.path.exists(".env.mam-backup"))
핵심 원칙: 보존 계열 단언에 or를 쓰지 않습니다. or 대안지는 실패 양상을 흡수합니다.
5. 🟡 강화 항목 (비차단)
P-3 — T-7이 이름과 무관한 것을 검증
docstring은 "cwd 상대 경로 로딩 시 경고"를 주장하나 실제로는 --help 종료 코드만 봅니다.
조치: 임시 디렉터리에 .env를 두고 그곳을 cwd로 래퍼 실행 → stderr에 WARNING/deprecated 포함 단언. 불가하면 docstring을 실제 검증 내용(smoke: wrapper executes)으로 정정해 거짓 안전감을 제거.
P-4 — T-10/T-12의 공허한 통과 위험
T-10은 subprocess.run(...) 결과를 어디에도 단언하지 않습니다. install.sh가 초기 실패해도 통과합니다.
단, 현재는 진짜로 통과합니다 (재현 확인: EXITCODE=0, Preserved without shadowing, .mam.env 미생성). 문제는 미래 회귀를 못 잡는다는 점입니다.
조치: assertEqual(res.returncode, 0) + 섹션 5 도달 표지 문자열 단언.
self.assertEqual(res.returncode, 0, f"install.sh failed: {res.stderr}")
self.assertIn("Preserved without shadowing", res.stdout)
self.assertFalse(os.path.exists(".mam.env"))
P-5 — 미구현 테스트 T-11 / T-14 / T-15 (+ 신규 T-16 / T-17)
| ID | 검증 내용 | 방어 대상 |
|---|---|---|
| T-11 | 구 update.sh 전체 시퀀스 E2E → 종료 후 사용자 설정값이 실제로 로드됨 |
E12 섀도잉 |
| T-14 | update.sh 중도 실패 → restore_on_failure가 원래 이름으로 복원 |
M-4 트랩 대칭 |
| T-15 | .mam.env.pre-migrate.bak와 .mam.env.update-tmp 상호 미간섭 |
E15 슬롯 충돌 |
| T-16 🆕 | remove.sh -y→install.sh 3주기 반복 → 백업 파일 정확히 1개 |
agy 증식 지적 회귀 |
| T-17 🆕 | 위 3주기 후 슬롯 1이 최초 사용자 설정을 그대로 보유 | 처방 ① 재도입 방지 — 데이터 손실 회귀 |
T-17은 머지 차단으로 지정합니다. §1에서 실측으로 재현된 비가역 데이터 손실의 회귀 가드이기 때문입니다. (재현된 결함에만 차단을 부여한다는 본 계획서의 일관된 기준에 부합합니다.)
T-11은 Rev.2 명세상 차단이었으나, 코드 검토상 update.sh:171-176 복원 분기가 대칭이고 실동작 결함이 재현되지 않아 최우선 강화 항목으로 유지합니다. 리뷰어가 이견을 제시하면 원안(차단)으로 복귀합니다.
P-6 — BOOTSTRAP .gitignore 예시의 유령 파일 참조
BOOTSTRAP.md:126-130 / BOOTSTRAP.ko.md:126-130의 !.env.example은 rename으로 더 이상 존재하지 않는 파일의 예외 규칙이며 실제 .gitignore(:17-22)와도 불일치합니다. 레거시 2줄(.env, .env.*)은 구 사용자 보호를 위해 유지가 타당합니다.
조치: !.env.example 줄 제거 또는 # legacy — 구 설치 호환용 주석 병기.
P-7 — CURRENT_JOB.md 처리
세션 UUID·에이전트 상태 등 휘발성 런타임 정보를 담은 untracked 문서이며 §3의 lib.sh 오기를 포함합니다.
권고: 커밋하지 않고 .gitignore에 등재.
6. 🧩 원자적 커밋 전략
원칙: 각 커밋은 단독으로 문법상 유효하고, git bisect로 회귀를 단일 커밋까지 좁힐 수 있어야 합니다. 파일이 아니라 관심사 기준으로 자릅니다.
| # | 커밋 | 대상 | 메시지(안) |
|---|---|---|---|
| C1 | 템플릿 rename + ignore 규칙 (+P-7) | .mam.env.example(staged rename), .gitignore |
refactor(config): rename .env.example to .mam.env.example and isolate .mam.env in gitignore |
| C2 | dotenv 로더 경계 수정 | …/scripts/mqtt_common.py |
fix(config): resolve dotenv via workspace marker and prefer .mam.env over legacy .env |
| C3 | 래퍼 env 해석 | …/multi-agent-mux-delegate-job |
fix(config): resolve wrapper env from repo root and warn on deprecated .env |
| C4 | 생성 스크립트 | deploy/generate-env.sh |
feat(deploy): target .mam.env and add --migrate-legacy flag |
| C5 | 설치기 (M-1 + M-2) | deploy/install.sh, deploy/install_mam.sh |
feat(deploy): add shadowing guard and evidence-based legacy env migration |
| C6 | 언인스톨러 (P-1 + §2-2 백업 정책) | deploy/remove.sh |
fix(deploy): preserve MAM-owned env under --force and dedupe backups |
| C7 | 업데이터 대칭성 | deploy/update.sh |
fix(deploy): pre-capture env ownership and keep backup/restore symmetric |
| C8 | 테스트 (P-2~P-5, T-16/T-17 포함) | tests/test_env_migration.py |
test: cover .mam.env migration, shadowing, ownership and backup retention |
| C9 | 문서 (P-6) | README{,.ko}.md, BOOTSTRAP{,.ko}.md, MULTI_AGENT_RULES{,.ko}.md, deploy/README.md |
docs: document .mam.env config file and legacy migration path |
순서 제약 (2건, 필수)
- C1 → C5:
install.sh가.mam.env.example을 참조하므로 rename이 선행해야 합니다. - C6 → C8: C8의 T-8/T-16/T-17은 C6의 수정이 있어야 통과합니다. 역순이면 중간 커밋이 red가 되어 bisect가 오염됩니다.
커밋 주체: MULTI_AGENT_RULES.md §4에 따라 구현·커밋은 Creator/GM 권한입니다. Planner는 설계 자산만 산출하며 코드를 수정하지 않습니다.
7. ✅ 완료 정의 (DoD) — 리뷰어 검증 게이트
게이트 A — 정적
for f in deploy/*.sh; do bash -n "$f"; done무오류git check-ignore -v .mam.env .mam.env.bak .mam.env.update-tmp .mam.env.mam-backup전부 매칭git check-ignore .mam.env.example비매칭 — 템플릿은 추적 대상*.tmp잔여물 없음
게이트 B — 데이터 보존 (P-1 회귀 · 차단)
5. 매니페스트 .env 기재 + remove.sh -y → .env.mam-backup 존재 + 원본 내용 보존
6. remove.sh --purge-env → 삭제됨 (의도적 삭제 경로 정상)
7. 매니페스트 없는 사용자 소유 .env → 어떤 플래그로도 원본 보존
게이트 B′ — 백업 위생 (agy 지적 반영 · 신규)
8. remove.sh -y→install.sh 3주기 반복 → 백업 파일 정확히 1개 (증식 없음)
9. 위 3주기 후 슬롯 1(*.mam-backup)이 최초 사용자 설정을 그대로 보유 — 차단
10. 내용이 다른 설정 2종을 연속 보존 시 둘 다 살아 있음 (dedup이 과잉 삭제하지 않음)
11. remove.sh -y stdout에 --purge-env 안내 문구 포함
게이트 C — 섀도잉 방지 (M-1 회귀 · 차단)
12. .env.update-tmp만 있는 상태로 install.sh → .mam.env 미생성, 종료코드 0, 섹션 5 도달 표지 포함
13. 매니페스트 없는 MQTT_BROKER 포함 .env → 이관 안 됨 (휴리스틱 탈취 방지)
14. 매니페스트 있는 .env → 이관 + chmod 0600 + 매니페스트 항목 치환
게이트 D — 테스트 품질 (P-2 회귀 · 차단)
15. tests/test_env_migration.py 전량 통과
16. 보존 계열 단언에 or 대안지 없음 — 정적 검토. assertTrue(A or not B) 금지
17. 각 subprocess 호출 테스트가 returncode를 단언
게이트 E — 회귀
18. pytest tests/test_tier1_unit.py tests/test_tier2_component.py tests/test_env_migration.py 통과
- 기준선 62 passed / 461s(7분41초). 느릴 뿐 회귀 아님. 타임아웃 300초 이상 필요
19. tier3/tier4는 P-1/P-2 수정 후 최소 1회 완주
게이트 F — 문서
20. 잔존 .env 참조가 전부 (a) 레거시 호환 로직, (b) 마이그레이션 안내, (c) 명시적 deprecated 표기 중 하나에 해당
8. ⚠️ 리스크 및 완화
| 리스크 | 심각도 | 완화 |
|---|---|---|
--force로 사용자 설정 비가역 소실 |
치명 · 비가역 | P-1 권한 분리 + P-2 T-8 재작성. 차단 |
| 단일 슬롯 덮어쓰기로 최초 백업 파괴 | 치명 · 비가역 | §2-2 슬롯 1 불변 + T-17 차단 가드. 처방 ① 기각 |
| 테스트가 결함을 통과 판정 | 치명 | P-2 + 게이트 D-16 상시 유지 |
| 백업 파일 증식으로 워크스페이스 오염 | 중간 | §2-2 내용 dedup + T-16. 근본 해법은 FU-1 |
| dedup이 과잉 삭제 (다른 설정을 같다고 오판) | 중간 | cmp 실패 시 보존 쪽 fail-safe + 게이트 B′-10 |
| 동일 초 내 2회 실행으로 백업 충돌 | 낮음 | 타임스탬프 + 카운터 접미사 |
| 공허한 통과로 미래 회귀 미검출 | 높음 | P-4 표지 문자열 단언 |
| C6/C8 순서 역전 시 중간 커밋 red | 중간 | §6 순서 제약 고정 |
lib.sh 오기 근거의 불필요한 수정 |
중간 | §3 명시 — dotenv 참조 0건, 범위 제외 |
9. 실행 순서 요약
- P-1
remove.sh삭제 권한 분리 + §2-2 백업 dedup/불변 정책 → C6 - P-2 T-8 재작성 + T-8b 신설 → C8
- P-3/P-4 T-7 정정, T-10/T-12 단언 보강 → C8
- P-5 T-11/T-14/T-15 + T-16/T-17 신설 → C8
- P-6 BOOTSTRAP 예시 정리 → C9
- P-7
CURRENT_JOB.md.gitignore등재 → C1 - 게이트 A~F 전량 확인 (특히 B′-9는 차단)
- C1 → C9 순서로 원자적 커밋 (C1→C5, C6→C8 제약 준수)
- 리뷰어 재검증 요청
후속 과제 (범위 외)
- FU-1:
install.sh의 M-1 가드가*.mam-backup을 인지하여 기본값 생성 대신 복원하도록 개선. 증식의 근본 해소 + 재설치 UX 개선. 별도 설계·검증 필요.
10. 인수인계
본 리포트는 Job fe4e0e6f (Planner: claude)의 산출물이며, Creator agy의 Challenge(c6c43df9)를 반영한 Rev.2입니다.
agy의 증식 진단은 채택했고 실측으로 확인했습니다(3주기 → 백업 3개). 지적해 준 덕분에 Rev.1에는 없던 백업 위생 게이트(B′)가 추가되었습니다.- 다만 처방 ①(단일 슬롯 덮어쓰기)은 기각합니다. 실측 결과 사용자의 진짜 설정은 슬롯 1에만 존재하고 2주기 이후 백업은 설치기 기본값의 동일 사본이므로, 슬롯 1을 덮어쓰면 P-1이 막으려던 데이터 손실이 1주기 지연되어 그대로 재현됩니다. 대신 내용 기반 dedup + 슬롯 1 불변으로 동일한 위생 효과(백업 1개)를 데이터 손실 없이 달성합니다.
- 처방 ② 중
--no-backup신설은 기각(--purge-env와 중복 — 권한 붕괴 재발 위험), 안내 문구 강화는 채택했습니다. - 차단 항목은 P-1, P-2, T-17 3건입니다. 구현 및 커밋은 Creator/GM 소관이며 Planner는 코드를 수정하지 않았습니다.
[AGREEMENT: REACHED]