Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a875b137b6 | ||
|
|
5ddc0df523 | ||
|
|
b490713471 |
@@ -0,0 +1,118 @@
|
|||||||
|
# Code Review Report — Job 120ffb08
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Cross-code review of commit `b490713` ("fix(loop): eliminate tmp script copy and trap leak in delegate_job_safe (P2-1/B-6)"). The commit eliminates temporary script copies in the skill tree, removes a trap that caused loop lock early release (D1) in command substitution subshells, adds diagnostic error logging for failed delegations, adds startup self-healing cleanup of stale .tmp files, and replaces 1 text-based test with 4 new behavioral tests.
|
||||||
|
|
||||||
|
**Verdict: PASS** — All changes are functionally correct. 58/58 tests pass across 5 test files. All syntax checks pass. Findings are Low/Info severity only.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
Files reviewed (commit `b490713`, 4 files, +211/-18):
|
||||||
|
1. `.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh` — `delegate_job_safe` rewrite, diagnostic logging, startup cleanup
|
||||||
|
2. `tests/test_o3_scoped_guard.py` — 4 new behavioral tests replacing 1 old text-based test
|
||||||
|
3. `IMPROVEMENTS.md` — B-6 marked complete, B-12 (D1) documented
|
||||||
|
4. `LOG.md` — Change log entry
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Review Findings
|
||||||
|
|
||||||
|
### F1 (Low / Code Quality): `_extract_delegate_job_safe()` uses text parsing
|
||||||
|
|
||||||
|
**Location**: `test_o3_scoped_guard.py:148-156`
|
||||||
|
|
||||||
|
**Description**: The `_extract_delegate_job_safe()` helper extracts the function body from `run_loop.sh` via string search (`content.find("delegate_job_safe() {")` and `content.find("\n}\n", func_start)`). This is fragile if the function definition format changes (e.g., adding a space before `()`).
|
||||||
|
|
||||||
|
**Impact**: None currently — the format is stable and the assertion `assert func_start != -1` provides a clear failure message if parsing breaks.
|
||||||
|
|
||||||
|
**Recommendation**: No action required. Acceptable for a test helper.
|
||||||
|
|
||||||
|
### F2 (Info): `test_z9_probe_detects_the_defect` validates the test catches the bug
|
||||||
|
|
||||||
|
**Location**: `test_o3_scoped_guard.py:180-218`
|
||||||
|
|
||||||
|
**Description**: This test deliberately uses the OLD defective `delegate_job_safe` (with tmp copy + `trap _mam_release_guard EXIT`) inside a command substitution `$(delegate_job_safe submit --task test)`. It asserts `MARKER: RELEASED` — proving the trap fires in the subshell and releases the loop lock. This is excellent test design: it validates that the test suite would catch a regression if someone reintroduced the defect.
|
||||||
|
|
||||||
|
**Impact**: None — correct and valuable test.
|
||||||
|
|
||||||
|
**Recommendation**: No action required.
|
||||||
|
|
||||||
|
### F3 (Info): `test_z9_exit_code_and_diagnostics_propagation` omits `set -e`
|
||||||
|
|
||||||
|
**Location**: `test_o3_scoped_guard.py:255-281`
|
||||||
|
|
||||||
|
**Description**: This test deliberately omits `set -euo pipefail` to allow capturing the exit code via `delegate_job_safe submit --task test || rc=$?`. It verifies exit code propagation (`DELEGATE_RC: 7`), diagnostic logging (`delegate_job_safe failed (exit 7):`), and syntax check hint (`bash -n`).
|
||||||
|
|
||||||
|
**Impact**: None — correct test design for exit code testing.
|
||||||
|
|
||||||
|
**Recommendation**: No action required.
|
||||||
|
|
||||||
|
### F4 (Info): Startup self-healing cleanup
|
||||||
|
|
||||||
|
**Location**: `run_loop.sh:148`
|
||||||
|
|
||||||
|
**Description**: `rm -f "$REPO_ROOT/.agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job".*.tmp 2>/dev/null || true` cleans up stale .tmp files from previous runs that used the old code. The glob matches the old naming convention (`${orig_script}.${RANDOM}_$$.tmp`). The `2>/dev/null || true` ensures no error if no files match.
|
||||||
|
|
||||||
|
**Impact**: Correct — handles migration from old code gracefully.
|
||||||
|
|
||||||
|
**Recommendation**: No action required.
|
||||||
|
|
||||||
|
### F5 (Info): Diagnostic error logging placement
|
||||||
|
|
||||||
|
**Location**: `run_loop.sh:106-109`
|
||||||
|
|
||||||
|
**Description**: When `delegate_job_safe` fails (non-zero exit), it logs:
|
||||||
|
```
|
||||||
|
log_error "delegate_job_safe failed (exit $rc): $orig_script"
|
||||||
|
log_error " if this loop edits framework skills in place, check that file's syntax:"
|
||||||
|
log_error " bash -n \"$orig_script\""
|
||||||
|
```
|
||||||
|
The comment block (lines 90-101) explains why this is needed: callers' "Failed to register ..." branches are unreachable when the wrapper exits non-zero under `set -e` (the assignment aborts first), so diagnosis must be emitted inside `delegate_job_safe` itself.
|
||||||
|
|
||||||
|
**Impact**: Correct — provides actionable diagnostics for the most common failure mode (syntax errors in framework skills edited in-place during a loop).
|
||||||
|
|
||||||
|
**Recommendation**: No action required.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
### Syntax Checks
|
||||||
|
- `bash -n .agents/skills/multi-agent-mux-loop/scripts/run_loop.sh` — PASS
|
||||||
|
- `python3 -m py_compile tests/test_o3_scoped_guard.py` — PASS
|
||||||
|
|
||||||
|
### Test Suite
|
||||||
|
- `pytest tests/test_sanitize_and_mock_errors.py tests/test_sanity.py tests/test_o3_scoped_guard.py tests/test_herdr_shim_contract.py tests/test_b4_session_created.py -v`
|
||||||
|
- **Result: 58 passed in 22.54s**
|
||||||
|
|
||||||
|
### New Tests (test_o3_scoped_guard.py)
|
||||||
|
1. `test_z9_loop_lock_survives_delegation` — Verifies loop lock marker remains HELD after delegation with the new in-place code. PASS
|
||||||
|
2. `test_z9_probe_detects_the_defect` — Verifies the OLD defective code (tmp copy + trap) causes RELEASED, proving the test catches regressions. PASS
|
||||||
|
3. `test_z9_no_tmp_copy_left_in_skill_tree` — Verifies no .tmp files remain in the skill tree after delegation. PASS
|
||||||
|
4. `test_z9_exit_code_and_diagnostics_propagation` — Verifies exit code propagation (rc=7) and diagnostic logging (error message + bash -n hint). PASS
|
||||||
|
|
||||||
|
### Code Correctness Analysis
|
||||||
|
|
||||||
|
**delegate_job_safe rewrite**: The old code created a tmp copy (`cp "$orig_script" "$tmp_script"`), set a trap to clean it up, ran the copy, cleaned up, then re-set `trap _mam_release_guard`. The new code simply runs `bash "$orig_script" "$@"` in-place. This eliminates:
|
||||||
|
- B-6: Source tree pollution (no .tmp file created)
|
||||||
|
- D1: Loop lock early release (no `trap _mam_release_guard` in the subshell)
|
||||||
|
|
||||||
|
The `|| rc=$?` pattern correctly captures the exit code without `set -e` aborting the function, and the diagnostic logging provides actionable error messages for the most common failure mode.
|
||||||
|
|
||||||
|
**Startup cleanup**: The `rm -f .../*.tmp` line at startup provides self-healing for any stale .tmp files from previous runs that used the old code. The glob pattern and `2>/dev/null || true` are correct.
|
||||||
|
|
||||||
|
### Limitations
|
||||||
|
- shellcheck not available in environment (verified via `bash -n` instead)
|
||||||
|
- Full 256-test suite not re-run in this session (timed out); 58 directly-relevant tests pass
|
||||||
|
- IMPROVEMENTS.md and LOG.md changes are documentation-only, verified by reading
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
The commit correctly eliminates the temporary script copy (B-6) and the trap leak (D1) by running the delegate-job wrapper in-place without any trap installation. The diagnostic error logging provides actionable feedback when the wrapper fails. The startup self-healing cleanup handles migration from old code. The 4 new behavioral tests are well-designed — they verify the fix works, prove the test catches the defect, confirm no .tmp files leak, and validate exit code/diagnostics propagation. No blocking issues found.
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
# Cross-Code Review Report — Job 143de35c
|
||||||
|
|
||||||
|
- **Job ID**: 143de35c
|
||||||
|
- **Reviewer**: cline
|
||||||
|
- **Scope**: Verify P2-1 (B-6: Eliminate temporary script copy and trap leak in `delegate_job_safe`, commit `b490713`) is 100% completed and validated; audit `IMPROVEMENTS.md` backlog for remaining prioritized improvement opportunities (P2-2: C-3a + C-4, P2-3: C-6, P3-1: A-4 M2~M7).
|
||||||
|
- **Changes under review**: `(no changes since base commit)` — base commit is `b490713` (the P2-1 fix). Only delta since base is an archived review-report doc (`report-120ffb08.md`, +118 lines, non-code).
|
||||||
|
- **Date**: 2026-08-15
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. P2-1 (B-6 / B-12) Verification — ✅ 100% Complete & Validated
|
||||||
|
|
||||||
|
### 1.1 Source Code (`run_loop.sh`)
|
||||||
|
|
||||||
|
`delegate_job_safe()` at `.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh:102-112` implements the fix exactly as documented:
|
||||||
|
|
||||||
|
- **No temporary copy**: The wrapper is executed in-place via `bash "$orig_script" "$@"` (line 105). The previous `.tmp` copy-into-`.agents/skills/...` tree logic is fully removed.
|
||||||
|
- **No `trap`**: No `trap _mam_release_guard EXIT INT TERM HUP` exists inside `delegate_job_safe`. The explanatory comment (lines 90-101) documents *why* both the copy and the trap were removed (B-6 tree pollution + B-12 subshell trap-leak firing on `$(...)` command-substitution subshell exit, dropping the loop lock after the first delegated job).
|
||||||
|
- **Diagnostics**: A local `rc=0` captures the wrapper's exit code; on non-zero, `log_error` emits the previously-unreachable failure diagnosis (lines 106-110). Callers' own "Failed to register …" branches remain reachable for non-`set -e` paths.
|
||||||
|
- **Residual `.tmp` sweep**: Startup sweep of `.../multi-agent-mux-delegate-job.*.tmp` is retained for backwards cleanup of any pre-fix leftovers (confirmed in commit `b490713` diff, `run_loop.sh` +26 lines).
|
||||||
|
|
||||||
|
### 1.2 Commit Hygiene (`b490713`)
|
||||||
|
|
||||||
|
`git show b490713 --stat` — surgical, 4 files only:
|
||||||
|
| File | Δ |
|
||||||
|
|---|---|
|
||||||
|
| `run_loop.sh` | +26/-… |
|
||||||
|
| `IMPROVEMENTS.md` | +24 |
|
||||||
|
| `LOG.md` | +12 |
|
||||||
|
| `tests/test_o3_scoped_guard.py` | +167 |
|
||||||
|
|
||||||
|
No unrelated files touched. Every changed line traces to B-6/B-12. ✅
|
||||||
|
|
||||||
|
### 1.3 Tests
|
||||||
|
|
||||||
|
- `tests/test_o3_scoped_guard.py` + `tests/test_a4_adapter_contract.py` → **30 passed** (includes the 4 new Z-9 behavior-based tests: `test_z9_loop_lock_survives_delegation`, `test_z9_probe_detects_the_defect`, `test_z9_no_tmp_copy_left_in_skill_tree`, `test_z9_exit_code_and_diagnostics_propagation`).
|
||||||
|
- `tests/test_b7_diff_untracked.py` → **20 passed** (same `run_loop.sh` slot, confirms no regression).
|
||||||
|
- All relevant tests green; the Z-9 suite directly asserts both the "no tmp copy" (B-6) and "loop lock survives delegation" (B-12/D1) behaviors.
|
||||||
|
|
||||||
|
### 1.4 Syntax
|
||||||
|
|
||||||
|
- `bash -n run_loop.sh` → OK
|
||||||
|
- `bash -n lib.sh` → OK
|
||||||
|
- `bash -n stop_session.sh` → OK
|
||||||
|
|
||||||
|
### 1.5 Documentation (`IMPROVEMENTS.md`)
|
||||||
|
|
||||||
|
- `B-6` section (line 71): marked **✅ 완료 (Stage 1)** — describes in-place execution + residual `.tmp` sweep + failure diagnostics.
|
||||||
|
- `B-12` section (line 79): marked **✅ 완료 (P0)** — describes trap removal + Z-9 test replacement.
|
||||||
|
- `P2-1` consolidated section (line 125): marked **✅ 완료** — merges B-6 + B-12 with full rationale.
|
||||||
|
- Priority table 6.2 row `P2-1 | B-6` aligns with the completed state.
|
||||||
|
|
||||||
|
### 1.6 P2-1 Verdict
|
||||||
|
|
||||||
|
**P2-1 is 100% completed and validated.** Code, tests, syntax, and documentation are consistent and self-corroborating. The fix is minimal, surgical, and behaviorally proven by the Z-9 regression suite.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. IMPROVEMENTS.md Backlog Audit — Remaining Prioritized Opportunities
|
||||||
|
|
||||||
|
Per the brief, the remaining backlog was audited against the live codebase. The header states **10 unresolved items** (Architecture 2, Edge-cases 5, Orchestration 0, Legacy 3); §6.2 enumerates 12 roadmap rows (some are sub-items / decisions). Current status:
|
||||||
|
|
||||||
|
| Priority | Item | Status (live code audit) | Evidence |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **P2-2** | **C-3a** (4 empty isolation stubs) + **C-4** (dead symbols) | 🔴 **Not started** — all targets confirmed present | See §2.1, §2.2 |
|
||||||
|
| **P2-3** | **C-6** (`stop_session.sh` stale help text) | 🔴 **Not started** — defect confirmed live | See §2.3 |
|
||||||
|
| **P3-1** | **A-4 M2~M7** (adapter main migration) | 🟡 **Partially done** — only M0~M1 complete | See §2.4 |
|
||||||
|
| **P3-2** | **B-10** (`agent_identities` write path + PyYAML dep) | 🔴 Not started | §6.2 row; depends on A-4 M2 |
|
||||||
|
| **P3-3** | **C-3b** (`isolation.root` consumer disposition) | 🔴 Not started | §6.2 row; depends on A-4 M2 |
|
||||||
|
| **P4-1** | **B-9** (`LOGS_DIR` import-time cwd) | 🔴 Not started (low impact; 2 mitigations exist) | §6.2 row |
|
||||||
|
| **P5-1** | **A-2** (public broker + HMAC) | 🔴 Deferred by user instruction (P5) | §6.2 note |
|
||||||
|
| **종결 권고** | **B-5** (`df --output` GNU flag) | ⚪ Recommend close (fallback `df -P` works) | Line 75 |
|
||||||
|
| **—** | **B-11** (mount-point ERE interpolation) | 🟡 Split-off recommendation from B-5 residual | Line 75 |
|
||||||
|
| **—** | **B-13** (in-flight tooling mutation, Stage 2) | 🟡 Separated Stage 2 task | Line ~85 |
|
||||||
|
|
||||||
|
### 2.1 P2-2 / C-3a — 4 Empty Isolation Stubs (NOT done)
|
||||||
|
|
||||||
|
All 4 stubs remain in `lib.sh` with empty bodies, zero production callers:
|
||||||
|
- `provision_isolation()` — `lib.sh:1369`
|
||||||
|
- `isolation_lever()` — `lib.sh:1374`
|
||||||
|
- `isolation_env_prefix()` — `lib.sh:1381`
|
||||||
|
- `isolation_cmd_args()` — `lib.sh:1385`
|
||||||
|
|
||||||
|
Per §6.5, the 5 vacuous tests pinning these stubs (`test_tier1_unit.py` ×3, `test_tier2_component.py` ×1 + 1) are co-removal targets. **C-3b must NOT be touched** (intentionally revived in `b4a1d094`/`44062a63`). ✅ Audit consistent with live code.
|
||||||
|
|
||||||
|
### 2.2 P2-2 / C-4 — Dead Symbols (NOT done, list corrected to 3)
|
||||||
|
|
||||||
|
Live confirmation of the corrected 3-symbol target list:
|
||||||
|
- `_REAL_HERDR_PATH` — `lib.sh:126` (assignment + `export` only, no read) ✅ present
|
||||||
|
- `TERMINAL_STATUSES` — `multi-agent-mux-delegate-job/scripts/registry.py:38` (definition only, no reference) ✅ present
|
||||||
|
- `ISOLATE` — `multi-agent-mux-create/scripts/create_session.sh:57` (assignment only) ✅ present
|
||||||
|
|
||||||
|
**Excluded (per §6.5 correction, correctly left alone):** `_HERDR_SHIM_DIR_PATTERN` is *in use* (`lib.sh:57` → `lib.sh:79`); `local_herdr` already removed. Audit confirms the corrected list matches live code. ⚠️ Risk note: a naive "delete all 7" execution would break shim-path detection — §6.5 correction must be honored.
|
||||||
|
|
||||||
|
### 2.3 P2-3 / C-6 — `stop_session.sh` Stale Help (NOT done, defect live)
|
||||||
|
|
||||||
|
`.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh`:
|
||||||
|
- Header comment (line 5): advertises `[--mode soft|hard]`
|
||||||
|
- `usage()` (line 41): does **not** list `--mode`
|
||||||
|
- Option parser (line 65): `--mode|--capture-id|--graceful)` → falls through to `exit 2` ("unknown arg")
|
||||||
|
|
||||||
|
So the documented `--mode soft|hard` is rejected at runtime. ~3-line fix. ✅ Audit consistent — defect is live and reproducible.
|
||||||
|
|
||||||
|
### 2.4 P3-1 / A-4 — Adapter Layer (PARTIALLY done: M0~M1 only)
|
||||||
|
|
||||||
|
- **M0~M1 ✅ done**: `tests/test_a4_adapter_contract.py` → **3/3 PASS** (PYTHONPATH bootstrap, deploy/CI registration, `own_key` migration; fanout 34→29 per prototype).
|
||||||
|
- **M2~M7 🔴 not started**: `artifact_path`/`verify_artifact`, `spawn_spec`/`resume_spec`/`auth_ok`, `discover()`, `stop_session.sh` purge path, `ready_tokens` migration, claude `projects` removal. This is the large (大) remaining structural work; gating decision for B-10 / C-3b disposition happens here.
|
||||||
|
|
||||||
|
### 2.5 Backlog Audit Verdict
|
||||||
|
|
||||||
|
The backlog is **accurate and up-to-date** as of 2026-08-15. All "not started" items were confirmed present in live code; the §6.5 corrections (C-3 split, C-4 list reduction to 3, A-2 cause rewording, B-5/B-11 split) are reflected. No stale/false "completed" claims found. The next executable, dependency-free items are **P2-2 (C-3a + C-4)** and **P2-3 (C-6)** — both small, both reduce regression time / risk.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Lint / Behavioral / Loss Review
|
||||||
|
|
||||||
|
Since `(no changes since base commit)`, the review is a re-verification of `b490713` plus a non-code backlog audit:
|
||||||
|
|
||||||
|
- **Lint**: `bash -n` passes on all 3 touched/relevant shell scripts (`run_loop.sh`, `lib.sh`, `stop_session.sh`); no `py_compile` needed (no `.py` changed in b490713 except the test file). ✅
|
||||||
|
- **Behavioral**: Z-9 tests (30 passed) + B-7 tests (20 passed) prove no tmp copy, no trap leak, loop-lock survival, and exit-code/diagnostic propagation. ✅
|
||||||
|
- **Loss (regression/orphan check)**: `git diff b490713..HEAD --stat` shows only `report-120ffb08.md` (+118) — no code drift, no orphaned symbols introduced, no accidental removals. The b490713 commit removed the copy+trap and added diagnostics + tests; nothing was orphaned by it (the `_mam_release_guard` trap is still installed at loop scope, not inside `delegate_job_safe`). ✅
|
||||||
|
|
||||||
|
No `[ESCALATE: PLANNER]` warranted: P2-1 is a complete bug fix, and the remaining backlog items are already planned and prioritized in `IMPROVEMENTS.md` §6.2 — no re-planning/design-change needed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Summary
|
||||||
|
|
||||||
|
| Check | Result |
|
||||||
|
|---|---|
|
||||||
|
| P2-1 (B-6) tmp-copy elimination | ✅ Complete — in-place `bash "$orig_script"` |
|
||||||
|
| P2-1 (B-12) subshell trap-leak fix | ✅ Complete — no `trap` in `delegate_job_safe` |
|
||||||
|
| P2-1 tests (Z-9) | ✅ 30 passed |
|
||||||
|
| P2-1 syntax (`bash -n`) | ✅ OK |
|
||||||
|
| P2-1 commit hygiene | ✅ Surgical (4 files) |
|
||||||
|
| Backlog P2-2 (C-3a + C-4) | 🔴 Not started — targets confirmed live (corrected to 3+4) |
|
||||||
|
| Backlog P2-3 (C-6) | 🔴 Not started — stale `--mode` help confirmed live |
|
||||||
|
| Backlog P3-1 (A-4 M2~M7) | 🟡 M0~M1 done (3/3); M2~M7 pending |
|
||||||
|
| Backlog accuracy | ✅ Matches live code; §6.5 corrections honored |
|
||||||
|
| Lint / Behavior / Loss | ✅ Clean |
|
||||||
|
|
||||||
|
P2-1 is fully implemented, tested, and documented. The remaining backlog is accurately tracked and correctly prioritized; the next low-cost, dependency-free items are P2-2 and P2-3.
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
@@ -87,16 +87,27 @@ fi
|
|||||||
MAM_LOOP_MARKER="${MAM_LOOP_MARKER:-$REPO_ROOT/.mam/loop-guard-active}"
|
MAM_LOOP_MARKER="${MAM_LOOP_MARKER:-$REPO_ROOT/.mam/loop-guard-active}"
|
||||||
_mam_release_guard() { mam_release_loop_lock "$MAM_LOOP_MARKER" || true; }
|
_mam_release_guard() { mam_release_loop_lock "$MAM_LOOP_MARKER" || true; }
|
||||||
|
|
||||||
|
# Runs the delegate-job wrapper in place. Deliberately creates no copy and
|
||||||
|
# installs no trap:
|
||||||
|
# * a copy inside .agents/skills/ pollutes the source tree and leaks on
|
||||||
|
# SIGKILL (B-6). It never protected across turns anyway — the copy is made
|
||||||
|
# per call, so a wrapper broken in turn N is copied broken in turn N+1;
|
||||||
|
# * every call site is a command substitution, so a trap set here fires when
|
||||||
|
# that subshell ends. `$$` is still the parent's pid there, so
|
||||||
|
# _mam_release_guard passed its ownership check and dropped the loop lock
|
||||||
|
# after the first delegated job (D1).
|
||||||
|
# The callers' own "Failed to register ..." branches are unreachable when the
|
||||||
|
# wrapper exits non-zero (set -e aborts the assignment first), so the diagnosis
|
||||||
|
# has to be emitted here.
|
||||||
delegate_job_safe() {
|
delegate_job_safe() {
|
||||||
local orig_script="$REPO_ROOT/.agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job"
|
local orig_script="$REPO_ROOT/.agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job"
|
||||||
local tmp_script
|
|
||||||
tmp_script="${orig_script}.${RANDOM}_$$.tmp"
|
|
||||||
cp "$orig_script" "$tmp_script"
|
|
||||||
trap 'rm -f "$tmp_script"' EXIT INT TERM HUP
|
|
||||||
local rc=0
|
local rc=0
|
||||||
bash "$tmp_script" "$@" || rc=$?
|
bash "$orig_script" "$@" || rc=$?
|
||||||
rm -f "$tmp_script"
|
if [ "$rc" -ne 0 ]; then
|
||||||
trap _mam_release_guard EXIT INT TERM HUP
|
log_error "delegate_job_safe failed (exit $rc): $orig_script"
|
||||||
|
log_error " if this loop edits framework skills in place, check that file's syntax:"
|
||||||
|
log_error " bash -n \"$orig_script\""
|
||||||
|
fi
|
||||||
return $rc
|
return $rc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +145,7 @@ case "$_mam_acquire_rc" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
trap _mam_release_guard EXIT INT TERM HUP
|
trap _mam_release_guard EXIT INT TERM HUP
|
||||||
|
rm -f "$REPO_ROOT/.agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job".*.tmp 2>/dev/null || true
|
||||||
|
|
||||||
# --all-reviewer silently takes precedence over an explicit --reviewer list;
|
# --all-reviewer silently takes precedence over an explicit --reviewer list;
|
||||||
# warn so the discarded list isn't mistaken for having been honored (P2-1).
|
# warn so the discarded list isn't mistaken for having been honored (P2-1).
|
||||||
|
|||||||
+21
-3
@@ -74,8 +74,20 @@
|
|||||||
- **실측(ecef05a3)**: `df --output=target` 은 여전히 `rc=64` 로 실패하나 `ea36e81` 에서 추가된 `df -P` 폴백이 정상 동작합니다(macOS 실측: `/System/Volumes/Data`). **결론("감지 실패")은 더 이상 참이 아니므로 종결을 권고합니다.**
|
- **실측(ecef05a3)**: `df --output=target` 은 여전히 `rc=64` 로 실패하나 `ea36e81` 에서 추가된 `df -P` 폴백이 정상 동작합니다(macOS 실측: `/System/Volumes/Data`). **결론("감지 실패")은 더 이상 참이 아니므로 종결을 권고합니다.**
|
||||||
- **잔여분 → B-11 로 분리 권고**: `mount | grep -E "$mountpoint.*(nfs|cifs|smb|sshfs)"` 가 마운트포인트를 이스케이프 없이 ERE 에 보간하여 경로의 `.` 이 임의 문자로 해석됩니다(이론상 오탐).
|
- **잔여분 → B-11 로 분리 권고**: `mount | grep -E "$mountpoint.*(nfs|cifs|smb|sshfs)"` 가 마운트포인트를 이스케이프 없이 ERE 에 보간하여 경로의 `.` 이 임의 문자로 해석됩니다(이론상 오탐).
|
||||||
|
|
||||||
### **B-6: 스킬 트리에 임시 파일 복사 및 유출**
|
### **B-6: 스킬 트리에 임시 파일 복사 및 유출** — ✅ **완료 (Stage 1)**
|
||||||
- `run_loop.sh::delegate_job_safe`가 래퍼 스크립트를 `.agents/skills/...` 트리 내부에 `.tmp`로 복사하여 버전 관리 트리를 오염시키고 rsync 배포 시 외부로 유출됩니다.
|
- `run_loop.sh::delegate_job_safe`가 래퍼 스크립트를 `.agents/skills/...` 트리 내부에 `.tmp`로 복사하여 버전 관리 트리를 오염시키고 rsync 배포 시 외부로 유출되던 문제를, 임시 사본 생성 없이 원본 스크립트를 직접 인플레이스 실행(`bash "$orig_script" "$@"`)하도록 개선하여 해결했습니다.
|
||||||
|
- 기존에 이미 존재하던 완화 조치(`.gitignore:18`의 `*.tmp`, `deploy/install_mam.sh:126`의 `--exclude='*.tmp'`, `deploy/install.sh:190`의 `*.tmp` skip)에 더해, 소스 트리 내 누출 경로 자체를 소멸시켰습니다.
|
||||||
|
- `run_loop.sh` 기동 시 잔여 `.tmp` 스윕 구문(`rm -f .../multi-agent-mux-delegate-job.*.tmp`) 및 실패 시 진단 로깅을 추가했습니다.
|
||||||
|
|
||||||
|
### **B-12: 명령 치환 서브셸의 EXIT 트랩으로 인한 루프 락 조기 해제 (D1)** — ✅ **완료 (P0)**
|
||||||
|
- `run_loop.sh` 내 `PLAN_JOB_OUTPUT=$(delegate_job_safe submit ...)` 등 11개 호출부가 명령 치환(`$(...)`) 서브셸로 실행될 때, `delegate_job_safe` 내부의 `trap _mam_release_guard EXIT INT TERM HUP` 이 서브셸 종료 시 발화하는 결함입니다.
|
||||||
|
- bash 서브셸의 `$$` 가 부모 PID를 유지하므로 `mam_release_loop_lock` 의 소유권 검사를 통과하여 첫 번째 위임 잡 종료 시점에 `.mam/loop-guard-active` 마커가 삭제되었습니다.
|
||||||
|
- 이로 인해 O-3 Invocation-Aware Scoped Guard의 파일 수정 차단 및 O-2 단일 루프 락이 첫 번째 잡 이후 무력화되는 P0 결함을 `delegate_job_safe` 내 로컬 트랩을 전면 제거함으로써 근본 해결했습니다.
|
||||||
|
- `tests/test_o3_scoped_guard.py` 내 Z-9 테스트를 3종 행위 기반 테스트(`test_z9_loop_lock_survives_delegation`, `test_z9_probe_detects_the_defect`, `test_z9_no_tmp_copy_left_in_skill_tree`, `test_z9_exit_code_and_diagnostics_propagation`)로 교체하여 재발을 방지했습니다.
|
||||||
|
|
||||||
|
### **B-13: 셀프 호스팅 멀티에이전트 루프 중 턴 간 스킬 오염 (In-Flight Tooling Mutation)** — 🟡 **Stage 2 분리 과제**
|
||||||
|
- `/multi-agent-mux-loop` 가 `multi-agent-mux` 자체를 수정/리팩터링할 때, Turn 1에서 Worker가 `.agents/skills/...` 를 수정(문법 오류나 미완성 코드 포함)하면 후속 Turn 2의 Reviewer 잡 제출 시 래퍼가 비정상 종료되어 자가 치유(Corrective/Rebuttal) 단계로 진입하지 못하고 루프가 중단될 수 있는 위험입니다.
|
||||||
|
- Stage 1에서는 실패 시 명확한 구문 진단 로그(`log_error "delegate_job_safe failed (exit $rc)..."`)를 제공하도록 보강하였으며, 근본 해결을 위해 루프 기동 시 1회 임시 디렉터리에 런타임 스냅샷을 동결하는 Stage 2 구현(래퍼 지시문 경로 오버라이드 포함)이 제안되었습니다.
|
||||||
|
|
||||||
### **B-8: `send_keys_safe` agy 경로 검증 이탈**
|
### **B-8: `send_keys_safe` agy 경로 검증 이탈**
|
||||||
- agy 세션 주입 시 주입 실패 여부를 검증하지 않고 무조건 `return 0`을 남겨 실패 시에도 성공으로 보고됩니다.
|
- agy 세션 주입 시 주입 실패 여부를 검증하지 않고 무조건 `return 0`을 남겨 실패 시에도 성공으로 보고됩니다.
|
||||||
@@ -108,7 +120,13 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. 🎉 완료된 과제 (Completed Tasks — 12건)
|
## 5. 🎉 완료된 과제 (Completed Tasks — 13건)
|
||||||
|
|
||||||
|
### **P2-1 (B-6 / B-12): `delegate_job_safe` 임시 사본 제거 및 서브셸 루프 락 조기 해제 차단 조치** — ✅ 완료
|
||||||
|
- `.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh` 내 `delegate_job_safe` 가 `.agents/skills/...` 경로 내에 `.tmp` 사본을 생성하던 방식을 제거하고 원본 래퍼 스크립트를 인플레이스로 직접 실행(`bash "$orig_script" "$@"`)하도록 개선하여 버전 관리 트리 오염 및 rsync 배포 유출(B-6)을 완전히 해소했습니다.
|
||||||
|
- 명령 치환(`$(delegate_job_safe ...)`) 서브셸 내에 설치되던 `trap _mam_release_guard EXIT` 로 인해 첫 번째 위임 잡 종료 시점에 `.mam/loop-guard-active` 마커가 삭제되어 O-3 Scoped Guard 및 O-2 락이 무력화되던 인접 P0 결함(**B-12 / D1**)을 로컬 트랩 제거를 통해 근본 해결했습니다.
|
||||||
|
- 래퍼 스크립트 실행 실패 시 도달 불가능하던 에러 진단을 `delegate_job_safe` 내부에서 직접 표준오류로 출력(`log_error "delegate_job_safe failed (exit $rc)..."`)하도록 진단 로깅을 보강했습니다.
|
||||||
|
- `tests/test_o3_scoped_guard.py` 내 Z-9 테스트를 4개 세부 행위 기반 테스트(`test_z9_loop_lock_survives_delegation`, `test_z9_probe_detects_the_defect`, `test_z9_no_tmp_copy_left_in_skill_tree`, `test_z9_exit_code_and_diagnostics_propagation`)로 교체 검증했습니다.
|
||||||
|
|
||||||
### **multi-agent-mux-orc-onboard: 오케스트레이터 온보딩 스킬 및 `orchestrator_uuids` 배제 게이트 조치** — ✅ 완료
|
### **multi-agent-mux-orc-onboard: 오케스트레이터 온보딩 스킬 및 `orchestrator_uuids` 배제 게이트 조치** — ✅ 완료
|
||||||
- `.agents/skills/multi-agent-mux-orc-onboard/` 스킬 및 `.agents/skills/multi-agent-mux-orc-onboard/scripts/orc_onboard.sh` 헬퍼 모듈을 생성하여, 메인 오케스트레이터가 프로젝트 맥락 파악 시 자신의 대화 UUID를 포착해 `.mam/agent-sessions.yaml` 및 SQLite DB 내 `orchestrator_uuids` 리스트로 원자적 기록하는 구조를 구축했습니다.
|
- `.agents/skills/multi-agent-mux-orc-onboard/` 스킬 및 `.agents/skills/multi-agent-mux-orc-onboard/scripts/orc_onboard.sh` 헬퍼 모듈을 생성하여, 메인 오케스트레이터가 프로젝트 맥락 파악 시 자신의 대화 UUID를 포착해 `.mam/agent-sessions.yaml` 및 SQLite DB 내 `orchestrator_uuids` 리스트로 원자적 기록하는 구조를 구축했습니다.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# 📝 Multi-Agent Mux 작업 세션 기록 (`LOG.md`)
|
# 📝 Multi-Agent Mux 작업 세션 기록 (`LOG.md`)
|
||||||
|
|
||||||
- **최종 기록일시**: 2026-08-08 00:23 (KST)
|
- **최종 기록일시**: 2026-08-15 10:45 (KST)
|
||||||
- **작업 저장소**: `tmpl/multi-agent-mux` (Branch: `main`)
|
- **작업 저장소**: `tmpl/multi-agent-mux` (Branch: `main`)
|
||||||
- **작업 상태**: 모든 작업 완료, 세션 안전 종료(stopped), 저장소 상태 Clean!
|
- **작업 상태**: 모든 작업 완료, 세션 안전 종료(stopped), 저장소 상태 Clean!
|
||||||
|
|
||||||
@@ -8,7 +8,15 @@
|
|||||||
|
|
||||||
## 📌 1. 금일 작업 내용 요약
|
## 📌 1. 금일 작업 내용 요약
|
||||||
|
|
||||||
### 1) **multi-agent-mux-orc-onboard: 오케스트레이터 온보딩 스킬 및 `orchestrator_uuids` 배제 게이트 구축** — **완료**
|
### 1) **P2-1 (B-6 / B-12): `delegate_job_safe` 임시 사본 제거 및 서브셸 루프 락 조기 해제 차단 조치** — **완료**
|
||||||
|
- **배경**: `run_loop.sh::delegate_job_safe` 가 `.agents/skills/...` 내부에 `.tmp` 사본을 생성하여 트리 오염 및 배포 시 유출(B-6)되던 문제와, 명령 치환 서브셸 내의 `trap _mam_release_guard EXIT` 로 인해 첫 번째 잡 위임 시 루프 락 마커(`.mam/loop-guard-active`)가 조기 삭제되어 O-3 가드레일이 무력화되던 결함(**B-12 / D1**) 조치.
|
||||||
|
- **주요 구현**:
|
||||||
|
- [`.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh): `delegate_job_safe` 를 임시 사본 및 서브셸 트랩 없이 인플레이스로 직접 실행(`bash "$orig_script" "$@"`)하도록 개선하고 실패 시 진단 로깅 추가. 루프 기동 시 기존 잔여 `.tmp` 스윕 구문 추가.
|
||||||
|
- [`IMPROVEMENTS.md`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/IMPROVEMENTS.md): B-6 완료 상태 갱신, B-12 (D1) 결함 명세 및 B-13 (턴 간 스킬 오염) Stage 2 과제 등록.
|
||||||
|
- [`tests/test_o3_scoped_guard.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/tests/test_o3_scoped_guard.py): 취약한 문자열 검사 Z-9를 4개 행위 기반 테스트(`test_z9_loop_lock_survives_delegation`, `test_z9_probe_detects_the_defect`, `test_z9_no_tmp_copy_left_in_skill_tree`, `test_z9_exit_code_and_diagnostics_propagation`)로 교체.
|
||||||
|
- **검증**: `pytest tests/ -q` 실행 결과 **259 passed (100%)** 달성.
|
||||||
|
|
||||||
|
### 2) **multi-agent-mux-orc-onboard: 오케스트레이터 온보딩 스킬 및 `orchestrator_uuids` 배제 게이트 구축** — **완료**
|
||||||
- **배경**: 오케스트레이터(`agy`)가 서브 에이전트 생성/정지/복원 시 자기 대화 UUID가 `agent-sessions.yaml` 서브 세션으로 오염 캡처되어 SQLite DB 락(`database is locked`) 및 대화 충돌이 발생하던 결함 조치.
|
- **배경**: 오케스트레이터(`agy`)가 서브 에이전트 생성/정지/복원 시 자기 대화 UUID가 `agent-sessions.yaml` 서브 세션으로 오염 캡처되어 SQLite DB 락(`database is locked`) 및 대화 충돌이 발생하던 결함 조치.
|
||||||
- **주요 구현**:
|
- **주요 구현**:
|
||||||
- [`.agents/skills/multi-agent-mux-orc-onboard/SKILL.md`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-orc-onboard/SKILL.md) 및 [`.agents/skills/multi-agent-mux-orc-onboard/scripts/orc_onboard.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-orc-onboard/scripts/orc_onboard.sh): 오케스트레이터의 신원 UUID를 포착하여 `.mam/agent-sessions.yaml` 및 SQLite DB 내 `orchestrator_uuids` 리스트로 원자적 등록하는 스킬 구축.
|
- [`.agents/skills/multi-agent-mux-orc-onboard/SKILL.md`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-orc-onboard/SKILL.md) 및 [`.agents/skills/multi-agent-mux-orc-onboard/scripts/orc_onboard.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-orc-onboard/scripts/orc_onboard.sh): 오케스트레이터의 신원 UUID를 포착하여 `.mam/agent-sessions.yaml` 및 SQLite DB 내 `orchestrator_uuids` 리스트로 원자적 등록하는 스킬 구축.
|
||||||
|
|||||||
@@ -147,16 +147,171 @@ def test_z8_dead_pid_marker(mam_sandbox):
|
|||||||
assert res["decision"] == "allow"
|
assert res["decision"] == "allow"
|
||||||
|
|
||||||
|
|
||||||
# Z-9: delegate_job_safe restores _mam_release_guard trap
|
def _extract_delegate_job_safe():
|
||||||
def test_z9_delegate_job_safe_restores_trap():
|
|
||||||
run_loop = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-loop" / "scripts" / "run_loop.sh"
|
run_loop = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-loop" / "scripts" / "run_loop.sh"
|
||||||
content = run_loop.read_text()
|
content = run_loop.read_text()
|
||||||
# Check inside delegate_job_safe definition that trap - is replaced with trap _mam_release_guard
|
|
||||||
func_start = content.find("delegate_job_safe() {")
|
func_start = content.find("delegate_job_safe() {")
|
||||||
assert func_start != -1
|
assert func_start != -1
|
||||||
func_body = content[func_start:func_start+400]
|
func_end = content.find("\n}\n", func_start)
|
||||||
assert "trap _mam_release_guard EXIT INT TERM HUP" in func_body
|
assert func_end != -1
|
||||||
assert "trap - EXIT INT TERM HUP" not in func_body
|
return content[func_start:func_end + 3]
|
||||||
|
|
||||||
|
|
||||||
|
# Z-9: delegate_job_safe preserves loop lock across delegations without tmp copies/traps (B-6, D1)
|
||||||
|
def test_z9_loop_lock_survives_delegation(tmp_path):
|
||||||
|
loop_lock_sh = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-loop" / "scripts" / "loop_lock.sh"
|
||||||
|
skill_dir = tmp_path / ".agents" / "skills" / "multi-agent-mux-delegate-job"
|
||||||
|
skill_dir.mkdir(parents=True)
|
||||||
|
stub_wrapper = skill_dir / "multi-agent-mux-delegate-job"
|
||||||
|
stub_wrapper.write_text("#!/usr/bin/env bash\necho 'JOB_ID: 12345678'\n")
|
||||||
|
stub_wrapper.chmod(0o755)
|
||||||
|
|
||||||
|
extracted_func = _extract_delegate_job_safe()
|
||||||
|
script = f"""#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
REPO_ROOT="{tmp_path}"
|
||||||
|
MAM_LOOP_MARKER="$REPO_ROOT/.mam/loop-guard-active"
|
||||||
|
source "{loop_lock_sh}"
|
||||||
|
|
||||||
|
log_error() {{ echo "ERROR: $@" >&2; }}
|
||||||
|
log_info() {{ echo "INFO: $@" >&2; }}
|
||||||
|
|
||||||
|
_mam_release_guard() {{ mam_release_loop_lock "$MAM_LOOP_MARKER" || true; }}
|
||||||
|
|
||||||
|
mam_acquire_loop_lock "$MAM_LOOP_MARKER"
|
||||||
|
trap _mam_release_guard EXIT INT TERM HUP
|
||||||
|
|
||||||
|
{extracted_func}
|
||||||
|
|
||||||
|
PLAN_JOB_OUTPUT=$(delegate_job_safe submit --task test)
|
||||||
|
|
||||||
|
if [ -f "$MAM_LOOP_MARKER" ]; then
|
||||||
|
echo "MARKER: HELD"
|
||||||
|
else
|
||||||
|
echo "MARKER: RELEASED"
|
||||||
|
fi
|
||||||
|
"""
|
||||||
|
res = subprocess.run(["bash", "-c", script], capture_output=True, text=True)
|
||||||
|
assert res.returncode == 0
|
||||||
|
assert "MARKER: HELD" in res.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_z9_probe_detects_the_defect(tmp_path):
|
||||||
|
loop_lock_sh = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-loop" / "scripts" / "loop_lock.sh"
|
||||||
|
skill_dir = tmp_path / ".agents" / "skills" / "multi-agent-mux-delegate-job"
|
||||||
|
skill_dir.mkdir(parents=True)
|
||||||
|
stub_wrapper = skill_dir / "multi-agent-mux-delegate-job"
|
||||||
|
stub_wrapper.write_text("#!/usr/bin/env bash\necho 'JOB_ID: 12345678'\n")
|
||||||
|
stub_wrapper.chmod(0o755)
|
||||||
|
|
||||||
|
defective_func = """
|
||||||
|
delegate_job_safe() {
|
||||||
|
local orig_script="$REPO_ROOT/.agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job"
|
||||||
|
local tmp_script
|
||||||
|
tmp_script="${orig_script}.${RANDOM}_$$.tmp"
|
||||||
|
cp "$orig_script" "$tmp_script"
|
||||||
|
trap 'rm -f "$tmp_script"' EXIT INT TERM HUP
|
||||||
|
local rc=0
|
||||||
|
bash "$tmp_script" "$@" || rc=$?
|
||||||
|
rm -f "$tmp_script"
|
||||||
|
trap _mam_release_guard EXIT INT TERM HUP
|
||||||
|
return $rc
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
script = f"""#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
REPO_ROOT="{tmp_path}"
|
||||||
|
MAM_LOOP_MARKER="$REPO_ROOT/.mam/loop-guard-active"
|
||||||
|
source "{loop_lock_sh}"
|
||||||
|
|
||||||
|
log_error() {{ echo "ERROR: $@" >&2; }}
|
||||||
|
log_info() {{ echo "INFO: $@" >&2; }}
|
||||||
|
|
||||||
|
_mam_release_guard() {{ mam_release_loop_lock "$MAM_LOOP_MARKER" || true; }}
|
||||||
|
|
||||||
|
mam_acquire_loop_lock "$MAM_LOOP_MARKER"
|
||||||
|
trap _mam_release_guard EXIT INT TERM HUP
|
||||||
|
|
||||||
|
{defective_func}
|
||||||
|
|
||||||
|
PLAN_JOB_OUTPUT=$(delegate_job_safe submit --task test)
|
||||||
|
|
||||||
|
if [ -f "$MAM_LOOP_MARKER" ]; then
|
||||||
|
echo "MARKER: HELD"
|
||||||
|
else
|
||||||
|
echo "MARKER: RELEASED"
|
||||||
|
fi
|
||||||
|
"""
|
||||||
|
res = subprocess.run(["bash", "-c", script], capture_output=True, text=True)
|
||||||
|
assert res.returncode == 0
|
||||||
|
assert "MARKER: RELEASED" in res.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_z9_no_tmp_copy_left_in_skill_tree(tmp_path):
|
||||||
|
loop_lock_sh = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-loop" / "scripts" / "loop_lock.sh"
|
||||||
|
skill_dir = tmp_path / ".agents" / "skills" / "multi-agent-mux-delegate-job"
|
||||||
|
skill_dir.mkdir(parents=True)
|
||||||
|
stub_wrapper = skill_dir / "multi-agent-mux-delegate-job"
|
||||||
|
stub_wrapper.write_text("#!/usr/bin/env bash\necho 'JOB_ID: 12345678'\n")
|
||||||
|
stub_wrapper.chmod(0o755)
|
||||||
|
|
||||||
|
extracted_func = _extract_delegate_job_safe()
|
||||||
|
script = f"""#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
REPO_ROOT="{tmp_path}"
|
||||||
|
MAM_LOOP_MARKER="$REPO_ROOT/.mam/loop-guard-active"
|
||||||
|
source "{loop_lock_sh}"
|
||||||
|
|
||||||
|
log_error() {{ echo "ERROR: $@" >&2; }}
|
||||||
|
log_info() {{ echo "INFO: $@" >&2; }}
|
||||||
|
|
||||||
|
_mam_release_guard() {{ mam_release_loop_lock "$MAM_LOOP_MARKER" || true; }}
|
||||||
|
|
||||||
|
mam_acquire_loop_lock "$MAM_LOOP_MARKER"
|
||||||
|
trap _mam_release_guard EXIT INT TERM HUP
|
||||||
|
|
||||||
|
{extracted_func}
|
||||||
|
|
||||||
|
PLAN_JOB_OUTPUT=$(delegate_job_safe submit --task test)
|
||||||
|
"""
|
||||||
|
res = subprocess.run(["bash", "-c", script], capture_output=True, text=True)
|
||||||
|
assert res.returncode == 0
|
||||||
|
tmp_files = list(skill_dir.glob("*.tmp"))
|
||||||
|
assert tmp_files == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_z9_exit_code_and_diagnostics_propagation(tmp_path):
|
||||||
|
loop_lock_sh = REPO_ROOT / ".agents" / "skills" / "multi-agent-mux-loop" / "scripts" / "loop_lock.sh"
|
||||||
|
skill_dir = tmp_path / ".agents" / "skills" / "multi-agent-mux-delegate-job"
|
||||||
|
skill_dir.mkdir(parents=True)
|
||||||
|
stub_wrapper = skill_dir / "multi-agent-mux-delegate-job"
|
||||||
|
stub_wrapper.write_text("#!/usr/bin/env bash\necho 'syntax error' >&2\nexit 7\n")
|
||||||
|
stub_wrapper.chmod(0o755)
|
||||||
|
|
||||||
|
extracted_func = _extract_delegate_job_safe()
|
||||||
|
script = f"""#!/usr/bin/env bash
|
||||||
|
REPO_ROOT="{tmp_path}"
|
||||||
|
MAM_LOOP_MARKER="$REPO_ROOT/.mam/loop-guard-active"
|
||||||
|
source "{loop_lock_sh}"
|
||||||
|
|
||||||
|
log_error() {{ echo "ERROR: $@" >&2; }}
|
||||||
|
log_info() {{ echo "INFO: $@" >&2; }}
|
||||||
|
|
||||||
|
_mam_release_guard() {{ mam_release_loop_lock "$MAM_LOOP_MARKER" || true; }}
|
||||||
|
|
||||||
|
mam_acquire_loop_lock "$MAM_LOOP_MARKER"
|
||||||
|
trap _mam_release_guard EXIT INT TERM HUP
|
||||||
|
|
||||||
|
{extracted_func}
|
||||||
|
|
||||||
|
rc=0
|
||||||
|
delegate_job_safe submit --task test || rc=$?
|
||||||
|
echo "DELEGATE_RC: $rc"
|
||||||
|
"""
|
||||||
|
res = subprocess.run(["bash", "-c", script], capture_output=True, text=True)
|
||||||
|
assert "DELEGATE_RC: 7" in res.stdout
|
||||||
|
assert "delegate_job_safe failed (exit 7):" in res.stderr
|
||||||
|
assert "bash -n" in res.stderr
|
||||||
|
|
||||||
|
|
||||||
# Z-10: Reused PID with stale lstart is NOT blocked
|
# Z-10: Reused PID with stale lstart is NOT blocked
|
||||||
|
|||||||
Reference in New Issue
Block a user