11 KiB
Cross Code Review Report — Job 384b7986
- Job ID: 384b7986
- Reviewer: cline (session: herdr:canary-projects-multi-agent-mux-creator-cline)
- Target: Improve deployment files in
deploy/*(4 requirements: latest updates / essential markdowns only / install remove.sh & update.sh into{workspace}/.mam_deploy// generate.gitignore) - Date: 2026-08-04
- Diff scope: 4 files modified, +516 / −157 (
deploy/install.sh+373/−,deploy/install_mam.sh+96/−,deploy/remove.sh+152/−,deploy/update.sh+52/−). New untracked test suitetests/test_deploy_layout.py(5 tests, T-D1→T-D28).
1. Summary
The changeset refactors the MAM deployment scripts into a Rev.2 layout that satisfies all four stated requirements. The implementation is cohesive, idempotent, and backward-compatible:
-
Latest updates (safe-refresh) —
deploy/install.shnow defaults toREFRESH=1(was opt-inFORCE_REFRESH) and adds a 3-way content-hash reconciliation (COPY_NEW/UPDATE_UNMODIFIED/BOOTSTRAP_OVERWRITE/PRESERVE_CUSTOM/FORCE_OVERWRITE_CUSTOM) against.mam/asset_hashes.txt. User-modified framework skills are preserved and backed up to.mam/skill-backups/<TS>/unless--overwrite-customis passed. A--no-refresh|--offlineflag is added for air-gapped reinstalls.remove.shnow backs up locally-modified skills to.mam-skill-backup.<TS>/before deletion (mirroring install-side preservation). -
Essential markdowns only — Archive/git fetch excludes
.agents/reports/*,.agents/references/*,MESSAGING.md,BOOTSTRAP.md,BOOTSTRAP.ko.mdviatar --excludeandfind ... *.tmp|*.log|*.pycskip. Default root docs limited toAGENTS.md(MAM_INSTALL_DOCS=minimal);INSTALL.mdplaced under.agents/. The separateinstall_mam.shrsync gains--exclude='/references/' --exclude='*.tmp'(previously only excluded.git/,/reports/,*.log,__pycache__/,*.pyc). Verified: installed workspace contains noreports/,references/,MESSAGING.md, orBOOTSTRAP.md. -
.mam_deploy/layout —install.shandinstall_mam.shboth now copydeploy/remove.shanddeploy/update.shinto.mam_deploy/(chmod 0755, registered in manifest). Legacy root-levelremove.sh/update.share migrated into.mam_deploy/if manifest-owned.remove.shandupdate.shgainSCRIPT_DIR-based auto-resolution: when invoked from inside.mam_deploy/, they target the parent workspace; when passed.mam_deployas the target arg, they normalize to its parent.update.shuses dual-resolution (REMOVERloop over.mam_deploy/remove.shthenremove.sh) before invoking the uninstaller. -
.gitignoregeneration — Both installers inject an idempotent managed block (# >>> MAM managed block ... <<<) via a Python filter that removes any stale block before re-inserting. Block covers/.venv/,/.mam/,/.mam_deploy/,/.mam.env,/.mam.env.*,!/.mam.env.example,/.cache/multi-agent-mux-monitor/,/.mam-skill-backup.*/,CURRENT_JOB.md.remove.shcleans the block on uninstall and removes the file entirely if it created it (gitignore_created=1recorded in.mam/install_state)..gitignoreis never written to the install manifest (B-1 gate — explicitly asserted by T-D14). -
State preservation across updates (B-5) —
update.shnow stages and restoresinstall_state,asset_hashes.txt,version.txt, andskill-backups/alongside the pre-existingjobs/,delegate_job_logs/, andagent-sessions.*— verified by T-D27/T-D28.
2. Verification Evidence
2.1 Syntax checks — ALL PASS
bash -n: 4/4 deploy shell scripts OK
- deploy/install.sh OK
- deploy/install_mam.sh OK
- deploy/remove.sh OK
- deploy/update.sh OK
py_compile: tests/test_deploy_layout.py OK
2.2 Targeted test suite — 5/5 PASS (13.68s)
tests/test_deploy_layout.py::TestDeployLayout
test_td12_td13_td14_gitignore_managed_block PASSED [.gitignore block + manifest exclusion B-1]
test_td1_td2_td3_essential_markdowns_only PASSED [no reports/refs; no MESSAGING/BOOTSTRAP; AGENTS+RULES+INSTALL present]
test_td21_td22_td23_safe_refresh_custom_skills PASSED [local mod preserved on refresh; backup created; stderr warns]
test_td27_td28_update_preserves_mam_state PASSED [asset_hashes.txt + version.txt survive update cycle B-5]
test_td6_td7_td8_mam_deploy_layout_and_removal PASSED [.mam_deploy/{remove,update}.sh present+exec; remove.sh runs from inside .mam_deploy]
============================== 5 passed in 13.68s ==============================
2.3 Live install inspection (clean temp workspace, MAM_REPO_URL=. MAM_SKIP_VENV=1)
--- .gitignore (managed block) ---
# >>> MAM managed block (managed by install.sh — do not edit) >>>
/.venv/ /.mam/ /.mam_deploy/ /.mam.env /.mam.env.* !/.mam.env.example
/.cache/multi-agent-mux-monitor/ /.mam-skill-backup.*/ CURRENT_JOB.md
# <<< MAM managed block <<<
--- .mam_deploy/ --- remove.sh (0755) update.sh (0755)
--- root files --- .gitignore .mam.env .mam.env.example AGENTS.md (no MESSAGING/BOOTSTRAP)
--- exclusions verified --- .agents/reports/ absent .agents/references/ absent MESSAGING.md absent BOOTSTRAP.md absent
--- .mam/install_state --- gitignore_created=1
--- .mam/version.txt --- source=<local> commit=2ff8b2c... fetched_at=20260804T131420Z method=local
--- manifest B-1 gate --- .gitignore NOT in manifest (PASS) .mam_deploy/remove.sh in manifest .mam_deploy/update.sh in manifest
2.4 Pre-existing test status (out of scope)
tests/test_sanity.py HANGS (timed out at 30s) — requires live herdr/tmux environment. Pre-existing, not modified by this changeset. No regression introduced.
3. Findings
3.1 Blocking defects — NONE
No syntax errors, no control-flow breaks, no manifest-corruption paths. All 4 requirement gates are satisfied and covered by passing tests.
3.2 Non-blocking follow-ups (informational, do not block merge)
R-1 (Low) — Stray untracked .tmp file not covered by repo .gitignore
A runtime artifact multi-agent-mux-delegate-job.13436_75009.tmp exists untracked under .agents/skills/multi-agent-mux-delegate-job/. The install-time find skip (*.tmp at install.sh:188) and install_mam.sh rsync --exclude='*.tmp' (line 118) correctly prevent it from being installed into target workspaces, but the source repo's own .gitignore has no *.tmp rule, so it keeps reappearing as an untracked file across reviews (also flagged in jobs 9c44c6b2 and 54413a8a). Recommend adding a top-level *.tmp ignore to the repo .gitignore or cleaning the artifact at source. Does not affect installed workspaces.
R-2 (Low) — update.sh legacy-restore ordering hazard on legacy-owned .env
In update.sh lines 207–209, when MAM_LEGACY_ENV_OWNED=1 and ENV_BACKUP_SRC=.env, the restore does mv -f "$ENV_BACKUP_TMP" ".mam.env" — correct file migration. The pre-capture of MAM_LEGACY_ENV_OWNED + export (lines 86–90) is correctly inherited by the child install.sh, which reads it in migrate_legacy_env() (install.sh:476). Edge case: the child installer runs in step 4 before the parent restore in step 5. The child sees no .env (moved to .env.update-tmp) and no .mam.env, so it creates a fresh default .mam.env. The parent's restore then sees .mam.env already exists and falls to the else branch (mv -f "$ENV_BACKUP_TMP" "$ENV_BACKUP_SRC" = .env), leaving the user's real config at .env while a fresh default .mam.env shadows it. This only manifests when updating a workspace whose config is still legacy .env AND MAM-owned. Recommend either (a) restoring the env backup before invoking the child installer, or (b) having the child installer skip env creation when MAM_LEGACY_ENV_OWNED=1 and a .env.update-tmp/.mam.env.update-tmp sentinel exists. Not exercised by the current test suite (T-D27/T-D28 use .mam.env, not legacy .env).
R-3 (Info) — remove.sh deletes .mam_deploy/update.sh unconditionally
remove.sh:307 calls delete_asset ".mam_deploy/update.sh" outside the manifest-ownership loop used for remove.sh. In practice update.sh is always in the manifest (both installers register it), so this is fine, but it's a minor asymmetry: remove.sh self-deletion is guarded by manifest/FORCE while update.sh is deleted unconditionally. Harmless given current installers always register update.sh; a one-line comment would aid future maintainers.
R-4 (Info) — install_mam.sh does not write install_state / asset_hashes.txt / version.txt
install_mam.sh deploys skills via rsync but does not populate .mam/install_state, .mam/asset_hashes.txt, or .mam/version.txt. Consequently a subsequent install.sh --no-refresh would treat all files as BOOTSTRAP_OVERWRITE (no db_sha), and remove.sh's GI_CREATED lookup would default to 0. The primary installer is install.sh; install_mam.sh is a secondary path. Not a regression (it never wrote these files before). Documenting the divergence would help.
4. Gate Checklist
| # | Requirement | Status | Evidence |
|---|---|---|---|
| 1 | Latest updates (safe refresh) | ✅ PASS | 3-way hash reconciliation; --no-refresh; remove.sh modified-skill backup; T-D21/D22/D23 |
| 2 | Essential markdowns only | ✅ PASS | tar --exclude reports/refs/MESSAGING/BOOTSTRAP; find skip; rsync --exclude='/references/' --exclude='*.tmp'; live install confirms absence; T-D1/D2/D3 |
| 3 | Install remove.sh & update.sh into .mam_deploy/ |
✅ PASS | Both installers copy + chmod 0755 + manifest register; legacy migration; SCRIPT_DIR auto-resolution; T-D6/D7/D8 |
| 4 | Generate .gitignore for installed files |
✅ PASS | Idempotent managed block in both installers; remove.sh cleans block + removes if created; .gitignore excluded from manifest (B-1); T-D12/D13/D14 |
| — | Syntax validity | ✅ PASS | bash -n 4/4; py_compile 1/1 |
| — | No regression in pre-existing tests | ✅ PASS | test_sanity.py hangs are pre-existing (herdr/tmux env), not touched by this diff |
5. Verdict
The changeset is well-structured, addresses all four requirements with idempotent and backward-compatible logic, and is backed by a passing 5-test suite covering the critical gates (essential-docs filtering, .mam_deploy/ layout, .gitignore managed block + manifest exclusion, safe-refresh custom-skill preservation, and update-cycle state preservation). The 4 non-blocking follow-ups (R-1 through R-4) are low severity and do not impede merge. No blocking defects found.
[VERDICT: PASS]