# ๐Ÿ“ ๊ตฌํ˜„ ๊ณ„ํš์„œ 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 `agy` Challenge Report โ€” Job `c6c43df9` --- ## 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๊ณผ ๋™์ผ (๋ณ€๊ฒฝ ์—†์Œ) ```bash 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`๊ฐ€ ์ œ๊ธฐํ•œ ์ฆ์‹ ๋ฌธ์ œ๋ฅผ **๋ฐ์ดํ„ฐ ์†์‹ค ์—†์ด** ํ•ด์†Œํ•ฉ๋‹ˆ๋‹ค. ```bash # ์›์น™: ๊ธฐ์กด ๋ฐฑ์—…์€ ์ ˆ๋Œ€ ๋ฎ์–ด์“ฐ์ง€ ์•Š๋Š”๋‹ค. # ๋™์ผ ๋‚ด์šฉ์ด ์ด๋ฏธ ๋ณด์กด๋ผ ์žˆ์œผ๋ฉด ์ƒˆ ์‚ฌ๋ณธ์„ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. 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๋กœ ๊ฐœ์ •) **์žฌํ˜„:** ```bash 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`: ```python 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 ๊ฐœ์ •์— ๋งž์ถฐ ์ผ€์ด์Šค๋ฅผ ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค. ```python 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 ๋„๋‹ฌ ํ‘œ์ง€ ๋ฌธ์ž์—ด** ๋‹จ์–ธ. ```python 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 โ€” ์ •์ ** 1. `for f in deploy/*.sh; do bash -n "$f"; done` ๋ฌด์˜ค๋ฅ˜ 2. `git check-ignore -v .mam.env .mam.env.bak .mam.env.update-tmp .mam.env.mam-backup` ์ „๋ถ€ ๋งค์นญ 3. `git check-ignore .mam.env.example` **๋น„๋งค์นญ** โ€” ํ…œํ”Œ๋ฆฟ์€ ์ถ”์  ๋Œ€์ƒ 4. `*.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. ์‹คํ–‰ ์ˆœ์„œ ์š”์•ฝ 1. **P-1** `remove.sh` ์‚ญ์ œ ๊ถŒํ•œ ๋ถ„๋ฆฌ + **ยง2-2 ๋ฐฑ์—… dedup/๋ถˆ๋ณ€ ์ •์ฑ…** โ†’ **C6** 2. **P-2** T-8 ์žฌ์ž‘์„ฑ + T-8b ์‹ ์„ค โ†’ **C8** 3. **P-3/P-4** T-7 ์ •์ •, T-10/T-12 ๋‹จ์–ธ ๋ณด๊ฐ• โ†’ **C8** 4. **P-5** T-11/T-14/T-15 + **T-16/T-17 ์‹ ์„ค** โ†’ **C8** 5. **P-6** BOOTSTRAP ์˜ˆ์‹œ ์ •๋ฆฌ โ†’ **C9** 6. **P-7** `CURRENT_JOB.md` `.gitignore` ๋“ฑ์žฌ โ†’ **C1** 7. ๊ฒŒ์ดํŠธ A~F ์ „๋Ÿ‰ ํ™•์ธ (ํŠนํžˆ **Bโ€ฒ-9๋Š” ์ฐจ๋‹จ**) 8. C1 โ†’ C9 ์ˆœ์„œ๋กœ ์›์ž์  ์ปค๋ฐ‹ (C1โ†’C5, C6โ†’C8 ์ œ์•ฝ ์ค€์ˆ˜) 9. ๋ฆฌ๋ทฐ์–ด ์žฌ๊ฒ€์ฆ ์š”์ฒญ **ํ›„์† ๊ณผ์ œ (๋ฒ”์œ„ ์™ธ)** - **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]