15 KiB
🛡️ Cross-Code Review: Job cfe439f6 — Auto UUID Capture & Pinning for Fresh Agent Sessions
- Job ID: cfe439f6
- Reviewer: cline
- Target: Review and implement robust automatic UUID capture and pinning mechanisms for fresh agent sessions (preventing null
session_id_ownafter create/onboard). Updatecreate_session.sh,reconcile.sh,lib.sh, and relevant skill/rule docs. - Change scope: 13 modified files + 1 new test file (uncommitted working-tree diff; 268 insertions, 62 deletions).
0. Verdict Summary
The implementation is sound and complete. The core goal — preventing a null session_id_own after create/onboard by assigning a UUID at creation time and confirming it on disk via the reconciler — is achieved through a coherent three-stage protocol: (1) create_session.sh generates a UUID via mam_gen_uuid and passes claude --session-id <uuid>, recording session_id_source: assigned / session_id_verified: false; (2) reconcile.sh drift C0 verifies the transcript materialized and promotes session_id_verified: true / last_visible_status: pinned; (3) resume_session.sh detects whether the transcript exists on disk and chooses --session-id (fresh) vs -r (resume). Path normalization (os.path.realpath / cd -P && pwd -P) is applied consistently across shell and Python, closing the symlink/trailing-slash key-mismatch class. Lint passes, the new 13-case suite is green, and there is no cross-regression. Five non-blocking findings are documented below; none require a design-level rework.
[VERDICT: PASS]
1. Change Inventory (verified against working tree)
| File | Change | Status |
|---|---|---|
.agents/MULTI_AGENT_RULES.md / .ko.md |
New "Session ID Lifecycle & Auto-Assignment Protocol" section (auto-assign, first-message materialization, C0 confirmation, C-ambiguous guard, path equivalence) | ✅ verified |
.agents/skills/lib.sh |
New mam_gen_uuid, mam_abs_workspace, mam_workspace_key, mam_session_iso_root; workspace_key → os.path.realpath; verify_session_uuid multi-line scan + revalidate shortcut + iso_root paths + ordering invariant; verify_tui_viewport simplified; find_workspace_uuid/verify_tui_viewport → mam_abs_workspace; _pane_capture JSON unwrap |
✅ verified |
create_session.sh |
mam_gen_uuid for claude; --session-id flag in CMD_FULL; session_id_source/session_id_verified fields in YAML |
✅ verified |
reconcile.sh |
row_agent() helper; drift C0 (assigned-ID confirmation); C-ambiguous guard (all 4 agents); os.path.realpath in drift-B A-1 gate; drift-C loops use row_agent() |
✅ verified |
resume_session.sh |
CLAUDE_ID_FLAG logic: --session-id if transcript unmaterialized, -r if exists; mam_workspace_key + mam_session_iso_root for path resolution |
✅ verified |
multi-agent-mux-create/SKILL.md |
Pitfalls updated: removed "don't trust --session-id" / "first message generates id"; added auto-assignment + materialization docs | ✅ verified |
multi-agent-mux-monitor/SKILL.md |
Drift C rewritten: C0 (assigned confirmation), C (unassigned materialize), C-ambiguous (multiple candidates) | ✅ verified |
multi-agent-mux-resume/SKILL.md |
CMD_FULL comment: --session-id vs -r based on transcript existence |
✅ verified |
IMPROVEMENTS.md |
Rev.2 (b4a1d094) completed-task entry | ✅ verified |
LOG.md |
Agent status stopped→running, "캡처 완료"→"복원 완료" |
✅ verified |
tests/conftest.py |
Mock extracts --session-id <uuid> from cmd; ws_abs = os.path.realpath(cwd) |
✅ verified |
tests/test_tier3_integration.py |
key = os.path.realpath(str(tmp_path))... |
✅ verified |
tests/test_uuid_target.py |
NEW — 13 tests (T-1..T-13) | ✅ verified |
git status --porcelain: M on 13 tracked files + ?? on tests/test_uuid_target.py (uncommitted — see R-4).
2. Lint / Static Checks
| Check | Command | Result |
|---|---|---|
| Shell syntax (lib.sh) | bash -n .agents/skills/lib.sh |
✅ PASS |
| Shell syntax (reconcile.sh) | bash -n .../reconcile.sh |
✅ PASS |
| Shell syntax (create_session.sh) | bash -n .../create_session.sh |
✅ PASS |
| Shell syntax (resume_session.sh) | bash -n .../resume_session.sh |
✅ PASS |
Embedded Python (_pane_capture) |
sed -n '1872,1882p' lib.sh | python3 -c 'compile(...)' |
✅ PASS |
workspace_key availability in reconcile |
exec(os.environ['MAM_VERIFY_PY']) at reconcile.sh:327 loads workspace_key + verify_session_uuid from shared VERIFY_SESSION_PYTHON |
✅ no NameError |
| Path-key parity | mam_workspace_key (shell tr '/_' '--') vs Python .replace("/","-").replace("_","-") — both over realpath/cd -P && pwd -P |
✅ verified by T-13 |
shellcheck is not installed locally (matches prior job convention); CI gate remains the authority for that check.
3. Operability / Logic Review
3.1 Create: auto-assignment (create_session.sh:148-157, 312-324)
SESSION_UUID="$(mam_gen_uuid)"for claude only (agy/hermes/cline don't accept--session-id).CMD_FULL="${RESOLVED_BIN} --dangerously-skip-permissions --session-id ${SESSION_UUID}".- YAML entry records
claude_session_id_own = assigned,session_id_source = 'assigned',session_id_verified = False,last_visible_status = "assigned (awaiting first message)". Correct — the row is created atomically with the assigned UUID, so there is no window wheresession_id_ownis null after create. This is the core fix for the stated goal.
3.2 Reconciler C0: assigned-ID confirmation (reconcile.sh:587-610)
- Iterates
session_id_source == 'assigned' and not session_id_verifiedrunning sessions. - Calls
verify_session_uuid(cwd, agent, uuid, s, mode="discover")— note discover mode, so the revalidate shortcut does NOT fire; the agent-specific transcript check runs (file exists, sessionId matches, cwd matches, epoch floor applies). - On success: promotes
session_id_verified = True,last_visible_status = 'pinned', reports drift class C "confirmed on disk". - Separation from drift C: drift C only processes sessions where
claude_session_id_ownis falsy (if s.get('claude_session_id_own'): continue). An assigned session has the UUID set, so drift C skips it. No double-processing. Correct.
3.3 Reconciler C-ambiguous guard (reconcile.sh:628-633, 678-683, 721-726, 765-770)
- For unassigned/legacy sessions, after scanning candidates,
if len(valid_candidates) > 1: reportsC-ambiguous, setslast_visible_status = "ambiguous: N candidates", does NOT pin. The== 1pin block is skipped. Correct — prevents random pinning when multiple transcripts match.
3.4 verify_session_uuid hardening (lib.sh:1173-1244)
- Ordering invariant (lib.sh:1199-1209): workspace-key check runs BEFORE the revalidate shortcut. Comment cites T-12. This prevents handing back an id that belongs to a different workspace purely because the row is assigned+unverified. Verified by T-12.
- Revalidate shortcut (mode=="revalidate" + assigned + unverified → return True): lets a freshly-resumed session validate before its transcript is rewritten. The workspace check still guards it. Correct.
- Multi-line scan (lib.sh:1219-1242): reads up to 50 lines looking for
sessionId == uuidandcwd. The old code read only the first line. This handles transcripts where the first line is aqueue-operationevent (no cwd) and the cwd appears on a lateruserline. Verified by T-2. - iso_root paths: claude uses
(iso_root + "/projects") if iso_root else c_dir; agy/hermes/cline useiso_root or home. Consistent with the isolation-root model. Verified by T-11.
3.5 Path normalization (lib.sh:813-823, 1174-1180; reconcile.sh:509-510; resume_session.sh:85-95)
mam_abs_workspace:( cd -P "$p" && pwd -P )— resolves symlinks to real path.mam_workspace_key: pipesmam_abs_workspacethroughtr '/_' '--'.- Python
workspace_key:os.path.realpath(path)then.replace("/","-").replace("_","-"). - These produce identical keys for absolute, trailing-slash,
..-dotdot, and symlink inputs. Verified by T-13 (4 variations). This closes the symlink-key-mismatch class that could cause a session to be invisible to the reconciler.
3.6 Resume flag selection (resume_session.sh:83-95)
CLAUDE_ID_FLAG="-r"default; if the transcript${_proj_dir}/${_ws_key}/${UUID}.jsonldoes NOT exist →--session-id(fresh spawn). Otherwise-r(resume)._proj_dirresolves viamam_session_iso_root(isolation root) orCLAUDE_PROJECT_DIR/$HOME/.claude/projects. Matchesverify_session_uuid's claude base path. Correct — this is the key mechanism preventing resume from failing on a freshly created (unmaterialized) session.
3.7 _pane_capture JSON unwrap (lib.sh:1864-1884)
- The herdr shim returns
{"result": {"read": {"text": "..."}}}. The new_pane_captureextractsresult.read.textand falls back to raw on any parse failure. Defensive and correct — keepsverify_tui_viewportworking against the JSON-wrapping shim.
3.8 verify_tui_viewport simplification (lib.sh:1338-1362)
- Removed 4 identical per-agent case branches (all did
grep -q "$base"). Now: flatten whitespace, fixed-string grep onbase_flat; regex fallback for absolute-path detection. Cleaner, equivalent behavior.
4. Test Results
| Suite | Command | Result |
|---|---|---|
| UUID target (new) | pytest tests/test_uuid_target.py -q |
13 passed (57.27s) |
| Pure-lib.sh subset (fast) | pytest test_t3 test_t12 test_t13 -v |
3 passed (0.40s) |
| Cross-regression (O-3+sanity+B-4) | pytest tests/test_o3_scoped_guard.py tests/test_sanity.py tests/test_b4_session_created.py -q |
47 passed (23.79s) |
Tier3 (modified realpath assertion) |
pytest tests/test_tier3_integration.py::test_integration_stop_purge_combination -q |
1 passed (36.61s) |
The 13-case test_uuid_target.py covers: T-1 create-assigned, T-2 assigned-ID promotion after materialize, T-3 different-cwd transcript not pinned, T-4 C-ambiguous (2 candidates), T-5 custom session name pinned, T-6..T-9 (agy/hermes/cline/legacy paths), T-10 path-variation resume (/, .., symlink), T-11 legacy isolation row, T-12 other-workspace revalidate fails (ordering invariant), T-13 shell/Python workspace_key equivalence across 4 path forms.
5. Findings (non-blocking)
R-1: Wrapper-mode SESSION_UUID clear leaves misleading cmd_full in YAML (create_session.sh:164-170, 156)
In the claude spawn() branch, when a wrapper binary is used ([ -x "$WRAPPER" ] && basename != claude, or --wrapper), SESSION_UUID="" is cleared after CMD_FULL was already built as ... --session-id <uuid>. The YAML therefore records pane.cmd_full containing --session-id <uuid> but claude_session_id_own = None / session_id_source = 'pending-discovery' (because assigned = os.environ.get('SESSION_UUID', '') or None reads the cleared value). The wrapper is expected to manage its own session-id, so functionally the session is discovered later via drift C — no runtime break. But the recorded cmd_full is cosmetically misleading. Severity: low. Suggested fix: rebuild CMD_FULL without --session-id in the wrapper branch (or clear it before CMD_FULL is composed and re-add only in the non-wrapper path).
R-2: drift-B still inlines name.endswith('-creator-<agent>') (reconcile.sh:494-500)
The drift-B auto-register section infers the agent from the session-name suffix inline, while the new row_agent() helper (reconcile.sh:567-578) does the same with a pane-metadata-first fallback. This is not a bug — drift-B processes herdr sessions not yet in YAML (no pane dict), so the name convention is the only signal and row_agent() would degrade to the same fallback. It is a missed consolidation opportunity only. Severity: cosmetic. Suggested fix: optionally call row_agent(t) (it falls back to name) for single-source consistency.
R-3: verify_session_uuid claude scan breaks on first cwd-bearing line (lib.sh:1234-1236)
The multi-line scan sets found_cwd and breaks on the first line carrying a cwd field, even if valid_session (sessionId match) hasn't been confirmed on that line. In real claude transcripts every line carries the same sessionId, so valid_session and found_cwd converge. The only risk is a pathological transcript whose first cwd line has a different sessionId, which would return False (safe direction — fails closed). Severity: low / safe-direction. No fix required; documented for completeness.
R-4: Changes uncommitted in working tree
git status shows 13 modified + 1 untracked file, none staged or committed. This matches the prior job's R-3 observation and is a process/policy note, not a code defect. The diff under review is the working-tree state. Suggested action: git add -A && git commit -m "feat(uuid): auto-assign & pin session UUID at create; reconcile C0 confirm + C-ambiguous + path canonicalization".
R-5: mam_session_iso_root spawns a Python process per resume (resume_session.sh:86, lib.sh:828-842)
mam_session_iso_root and mam_workspace_key each shell out to env_python. On the resume path this adds two Python startup costs. Correct and well-isolated; only a minor latency note for cold-resume. Severity: perf, non-blocking.
6. Completeness / Loss Check
| Aspect | Coverage |
|---|---|
Goal: no null session_id_own after create |
✅ T-1 asserts claude_session_id_own non-null + source=assigned + verified=False immediately after create |
| Goal: confirmation after first message | ✅ T-2 asserts verified=True + pinned after transcript materialize + one reconcile cycle |
| Goal: resume uses correct flag | ✅ T-10 exercises --session-id vs -r via --dry-run across path variations; resume_session.sh:83-95 logic matches verify path |
| Ambiguity defense | ✅ T-4 asserts C-ambiguous reported + no pinning for 2 candidates |
| Cross-workspace safety | ✅ T-12 asserts revalidate fails for assigned row of a different workspace (ordering invariant) |
| Path canonicalization | ✅ T-13 asserts shell/Python key equivalence across 4 path forms; conftest + tier3 use os.path.realpath |
| Orphaned code | None found — _pane_capture/verify_tui_viewport simplifications remove now-redundant branches; endswith at reconcile.sh:494-500 is a distinct context (drift-B), not an orphan |
| Doc/test sync | ✅ SKILL.md (create/monitor/resume) + MULTI_AGENT_RULES + IMPROVEMENTS all reflect the new protocol; conftest mock updated to honor --session-id |
| Cross-regression | ✅ 47/47 (O-3 + sanity + B-4) green — no regression to prior fixes |
7. Conclusion
The change set implements the auto-assignment-and-pinning protocol end-to-end with clean separation of concerns: create assigns, reconcile confirms (C0) and guards ambiguity (C-ambiguous), resume adapts to transcript existence. Path canonicalization is applied uniformly in shell and Python and is proven equivalent by T-13. The ordering invariant (workspace check before revalidate shortcut) closes the cross-workspace leakage class (T-12). Lint passes on all touched shell scripts and embedded Python; the new 13-case suite is fully green; cross-regression (47) and the modified tier3 test are green. Five non-blocking findings are recorded (R-1..R-5), none requiring design-level rework. The stated goal — preventing a null session_id_own after create/onboard — is met.
[VERDICT: PASS]