Files
multi-agent-mux/.agents/reports/canary-projects-multi-agent-mux-creator-cline/report-384b7986.md
T

107 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 suite `tests/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:
1. **Latest updates (safe-refresh)**`deploy/install.sh` now defaults to `REFRESH=1` (was opt-in `FORCE_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-custom` is passed. A `--no-refresh|--offline` flag is added for air-gapped reinstalls. `remove.sh` now backs up locally-modified skills to `.mam-skill-backup.<TS>/` before deletion (mirroring install-side preservation).
2. **Essential markdowns only** — Archive/git fetch excludes `.agents/reports/*`, `.agents/references/*`, `MESSAGING.md`, `BOOTSTRAP.md`, `BOOTSTRAP.ko.md` via `tar --exclude` and `find ... *.tmp|*.log|*.pyc` skip. Default root docs limited to `AGENTS.md` (`MAM_INSTALL_DOCS=minimal`); `INSTALL.md` placed under `.agents/`. The separate `install_mam.sh` rsync gains `--exclude='/references/' --exclude='*.tmp'` (previously only excluded `.git/`, `/reports/`, `*.log`, `__pycache__/`, `*.pyc`). Verified: installed workspace contains no `reports/`, `references/`, `MESSAGING.md`, or `BOOTSTRAP.md`.
3. **`.mam_deploy/` layout** — `install.sh` and `install_mam.sh` both now copy `deploy/remove.sh` and `deploy/update.sh` into `.mam_deploy/` (chmod 0755, registered in manifest). Legacy root-level `remove.sh`/`update.sh` are migrated into `.mam_deploy/` if manifest-owned. `remove.sh` and `update.sh` gain `SCRIPT_DIR`-based auto-resolution: when invoked from inside `.mam_deploy/`, they target the parent workspace; when passed `.mam_deploy` as the target arg, they normalize to its parent. `update.sh` uses dual-resolution (`REMOVER` loop over `.mam_deploy/remove.sh` then `remove.sh`) before invoking the uninstaller.
4. **`.gitignore` generation** — 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.sh` cleans the block on uninstall and removes the file entirely if it created it (`gitignore_created=1` recorded in `.mam/install_state`). `.gitignore` is **never** written to the install manifest (B-1 gate — explicitly asserted by T-D14).
5. **State preservation across updates (B-5)**`update.sh` now stages and restores `install_state`, `asset_hashes.txt`, `version.txt`, and `skill-backups/` alongside the pre-existing `jobs/`, `delegate_job_logs/`, and `agent-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 207209, 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 8690) 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]