Files
multi-agent-mux/.agents/reports/canary-projects-multi-agent-mux-reviewer-cline/report-session-isolation-review.md
T

9.2 KiB
Raw Blame History

Review Report — 세션 ID 격리 구현 (Session Isolation)

  • Reviewer: Reviewer Cline (canary-projects-multi-agent-mux-reviewer-cline, role: reviewer)
  • Date: 2026-07-10
  • Subject commit: 768cfe5 feat(isolation): implement Phase 1-3 session isolation with stop purge and resume safety
  • Range reviewed: HEAD~3..HEAD (commit 768cfe5 + 2 docs commits). ※ The user-requested HEAD~2..HEAD only spans the two docs commits and excludes the implementation commit itself (it sits at HEAD~2, excluded by an exclusive range); I expanded to HEAD~3..HEAD to cover the actual code, which is the evident intent.
  • Governing documents: AGENTS.md, .agents/MULTI_AGENT_RULES.md / .ko.md, implementation_plan.session_isolation.md (Rev.3), task.session_isolation.md

Verdict: PASS

The session-isolation implementation conforms to all three governing documents. All code implementation tasks (T1T6), including the RK2 resume re-apply fix and the T6 stop-purge with path safeguards, are complete and correct. bash -n passes; shellcheck introduces zero new warnings (V5 PASS); the non-isolated regression path is byte-identical (V4 PASS). Remaining unchecked items in task.session_isolation.md are live-integration verification steps (V1V3, T-V2) and an explicitly-optional orphan GC (T6-b) — they are process gates, not code defects, and are honestly flagged as pending by the developer.


1. Conformance to implementation_plan.session_isolation.md (Rev.3)

Phase 0 — 검증 게이트 (G2 프로브)

  • All G2 probes (G2-C1/C2, G2-L1, G2-A1, G2-H1, G2-M) are marked [x] in task.session_isolation.md.
  • §2.3 매트릭스 populated with per-agent lever, seed list, conversation path — including the two Rev.3 corrections: cline --config insufficient (seeding required) and cline isolated layout <root>/sessions/ (not data/sessions/).

Phase 1 — 공통 불변식 (T1/T2)

  • T1 claimed-set filter (lib.sh:543-573): running_ids set built from SQLite (DB-first) with YAML fallback; emit() filters any candidate already claimed by another running row. Target row's own IDs are excluded from the filter (if target and s_data.get('name') == target: continue) — fixes the self-ID filter bug noted in T5.
  • T2 생성-시 유일성 assert (lib.sh:386-399): iterates running rows, raises SystemExit on duplicate *_own across distinct sessions. Matches plan §2.4 R2.

Phase 2 — all-L2 격리 구현 (T3/T4/T5)

  • T3 provisioning (create_session.sh:119-135, lib.sh:818-856): uuidgen.mam/agent_homes/<uuid>/, per-agent symlink seeding, seeded list returned. Dry-run guard + error-trap rollback with path guard */.mam/agent_homes/* before rm -rf.
  • T4 spawn injection (lib.sh:858-882, create_session.sh:142-169): single dispatch via isolation_env_prefix (claude CLAUDE_CONFIG_DIR, agy/hermes HOME) and isolation_cmd_args (cline --data-dir). Applied to CMD_FULL, spawn(), and START_CMD. When ISOLATE=0, ISO_ENV_PREFIX=""/ISO_CMD_ARGS="" → strings reduce to exact pre-commit values (byte-identical, V4).
  • T5 schema persistence + re-apply (create_session.sh:311-320, lib.sh:501-504, 613-661): isolation: {uuid, root, lever, seeded[]} written via atomic_dump_yaml; _validate enforces uuid/root required. find_workspace_uuid target-mode resolves strictly within the row's isolation root — no global fallthrough (the C3 mtime bug is structurally eliminated). cline path template <root>/sessions/ correctly branched.

RK2 resume re-apply (previously flagged blocking — now fixed)

  • resolve_session_id.sh accepts --session and forwards to find_workspace_uuid "$WORKSPACE" "$AGENT" "$SESSION_NAME".
  • resume/SKILL.md workflow now: (1) passes --session "$SESSION_NAME", (2) resolves the row's isolation block via a Python helper, (3) re-derives ISO_ENV/ISO_ARGS via isolation_env_prefix/isolation_cmd_args, (4) prepends/appends to CMD_FULL before spawn. This satisfies T5's "저장+재적용은 원자적 세트" contract — the save path (create) and re-apply path (resume) share the same dispatch functions.

Phase 3 — stop 청소 (T6)

  • stop_session.sh:273-288: purge path guarded by two checks: (a) abspath(iso_root) == abspath(expected_iso_root) where expected_iso_root = <ws>/.mam/agent_homes/<iso_uuid>, and (b) startswith(expected_homes_dir + os.sep). Mismatch → WARN, no delete.
  • capture_conversation_id and find_workspace_uuid calls now pass $SESSION_NAME → isolated rows resolve within their own root, preventing cross-row UUID theft on purge.
  • T6-a (symlink original preservation): rmtree operates on iso_root only; symlink targets (real ~/.claude/.credentials.json etc.) are outside iso_root and untouched.

Phase 4 — 회귀 및 검증

ID Criterion Result
V4 Non-isolated path byte-identical (regression 0) PASS — verified: ISOLATE=0CMD_FULL equals pre-commit strings exactly
V5 bash -n + shellcheck new warnings = 0 PASS — bash -n OK; shellcheck diff vs 768cfe5~1 baseline shows 0 new (all 10 findings pre-existing, line-shifted only)
V1V3, T-V2 Live 4-agent simultaneous spawn + resume isolation Pending — explicitly marked [ ] by developer; scratch functional tests passed, live TUI multi-spawn remaining. Process gate, not a code defect.
T6-b Orphan GC (optional) Explicitly marked 선택(optional) in plan

2. Conformance to AGENTS.md

Simplicity First

  • No speculative features. provision_isolation is a per-agent case, not an over-generalized plugin system.
  • isolation_env_prefix/isolation_cmd_args are minimal one-liners — no abstraction beyond the 4-agent matrix.
  • Path guards use the simplest correct construct (case glob + os.path.abspath equality/startswith). No over-engineered allowlist framework.

Surgical Changes

  • Every changed line traces to a plan task (T1→T5, RK2, T6). No drive-by refactors.
  • Pre-existing shellcheck findings (SC2164 cd || exit, SC2034 unused i, SC2155 declare+assign, SC1091 source-not-followed) were not touched — correct per "Don't refactor things that aren't broken" and "Don't remove pre-existing dead code unless asked."
  • Non-isolated branches preserve original control flow and string literals verbatim.

Think Before Coding

  • The Phase 0 gate was honored: no Phase 2 code before the G2 matrix was finalized (plan §5 "Phase 0 게이트 통과 전 코드 구현 착수 금지").
  • Rev.3 decision log (D1D5) records the L1→all-L2 tradeoff explicitly rather than silently picking.

Goal-Driven Execution

  • task.session_isolation.md DoD items map 1:1 to plan tasks with verifiable criteria. Developer self-marked [x] only where evidence exists and left [ ] where verification is genuinely incomplete (honest reporting).

3. Conformance to MULTI_AGENT_RULES.md

  • Isolation root (.mam/agent_homes/<uuid>/) sits under .mam/.gitignore covered; included in the stop-cleanup contract (T6).
  • Symlink seeding (not copy) satisfies RK4 (token-refresh convergence on the real file) and avoids auth-divergence.
  • _validate schema enforcement for the isolation block (uuid/root required) keeps the registry internally consistent.
  • Role isolation: the implementation does not alter role semantics or cross into reviewer/PM authority — it is purely infrastructure (developer-team scope).
  • This report is persisted under .mam/reports/<tmux_session_name>/ per the markdown-collaboration protocol.

4. Observations (non-blocking, for record)

  1. hermes config.yaml embedded absolute paths (plan §2.3 note 3): the implementation symlinks config.yaml into the isolation root; hermes runtime resolves the symlink to the real config, which may reference real-HOME paths. The plan explicitly documents this as "읽기 공유라 무해하나, 격리 범위가 state/세션에 한정됨" — hermes isolation is scoped to state.db/sessions, not full config. Implementation matches the documented limitation. Not a defect.

  2. cline isolated layout divergence (<root>/sessions/ vs real ~/.cline/data/sessions/): correctly handled by cline_exists(uuid, iso) and the target-mode glob f"{iso}/sessions/*". Matches plan §2.3 note 2.

  3. Orphan GC (T6-b) remains unimplemented but is explicitly optional in the plan; .mam/ is gitignored and covered by remove.sh whole-tree cleanup. Not blocking.


5. Final Statement

The implementation is complete, correct against the approved Rev.3 plan, and respects AGENTS.md (Simplicity First / Surgical Changes) and MULTI_AGENT_RULES.md. The previously-blocking RK2 resume re-apply gap is resolved. Static verification (V4 byte-identical regression, V5 bash-n + shellcheck-new=0) passes. The remaining unchecked items are live-integration verification steps the developer has transparently left open — they do not represent code-level non-conformance.

PASS — approved for merge. Recommend the developer proceed with V1V3/T-V2 live-spawn integration verification as a follow-on gate before production rollout, per the plan's Phase 4 DoD.