docs(issue-34): --parent-job, MAM_CHILD_WAIT_S, --wait-open-jobs, the sub-job verdict rule and the stale-review guard
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
30c8c7ebab
commit
8690ef4bd2
4 files changed
+13
No files matched your search
@@ -151,6 +151,7 @@ TMUX 환경에서 실행되는 에이전트가 화면 스크롤 한계로 인해
|
||||
- **작업 위임**:
|
||||
- *수동 경로*: 상세 사양과 계획 수립 등의 복잡한 작업 지시는 먼저 로컬 마크다운 파일(예: `.mam/reports/brief-<job_id>.md` 또는 지정된 워크스페이스 경로)로 작성한 후, 에이전트에게 `"Read <파일경로> and execute."` 라는 실행 명령만 전달하십시오.
|
||||
- *자동 경로*: 자동화 잡 런너(`multi-agent-mux-delegate-job submit`)는 잡 등록 시 `.mam/jobs/<job_id>/brief.md` 디렉터리에 지시서를 자동 집필하고 단일 라인 포인터 프롬프트만 에이전트 세션에 인가합니다.
|
||||
- *하위 위임*: 자기 잡의 일부를 다시 위임하는 에이전트는 `submit` 에 `--parent-job <자기 job_id>` 를 붙입니다. 그래야 루프가 그 하위 잡을 기다리고 리뷰어에게 보여 줍니다(Issue #34).
|
||||
- **결과 안내 및 피드백**:
|
||||
- *수동/영구 리뷰*: 상세 리뷰 결과, 설계 제안서 등은 `.mam/reports/<tmux_session_name>/report-<job_id>.md` 경로에 저장합니다.
|
||||
- *자동화 잡 보고서*: 자동 위임된 비동기 작업의 완료 결과는 잡 디렉터리 하위인 `.mam/jobs/<job_id>/<agent_name>-reports/report-final.md` (루프/Discuss 위임 시에는 `<clean_session_name>-reports/`) 경로에 기록해야 합니다.
|
||||
|
||||
@@ -151,6 +151,7 @@ To ensure that agents running in TMUX environments do not lose debug logs or pre
|
||||
- **Task Delegation**:
|
||||
- *Manual path*: Detailed task briefs may be written to a local Markdown file (e.g., `.mam/reports/brief-<job_id>.md` or a workspace path) first. The sender then issues a simple trigger command: `"Read <file_path> and execute."`
|
||||
- *Automated path*: The automated job runner (`multi-agent-mux-delegate-job submit`) automatically provisions the brief at `.mam/jobs/<job_id>/brief.md` and sends a short pointer instruction to the agent.
|
||||
- *Sub-delegation*: an agent that delegates part of its job passes `--parent-job <its job_id>` to `submit`, so the loop waits for the sub-job and shows it to reviewers (Issue #34).
|
||||
- **Result Reporting & Feedback**:
|
||||
- *Manual/Durable reviews*: Detailed reviews, design proposals, or audit reports must be saved under `.mam/reports/<tmux_session_name>/report-<job_id>.md`.
|
||||
- *Automated job reports*: Automated execution results are saved directly to `.mam/jobs/<job_id>/<agent_name>-reports/report-final.md` (or `<clean_session_name>-reports/` for loops) as transient files.
|
||||
|
||||
@@ -46,6 +46,11 @@ multi-agent-mux-delegate-job submit \
|
||||
# must arrive within T s of the injection or the inject fails closed.
|
||||
# --prompt-file <path> replaces --prompt for long prompts (Issue #36): one
|
||||
# argv string is capped at 131,072 bytes on Linux. The loop always uses it.
|
||||
# --parent-job <id> (Issue #34): this job is delegated from job <id>, which
|
||||
# must exist in the registry (else exit 1). A loop waiting on <id> waits for
|
||||
# it too and shows it to reviewers. Default: $MAM_JOB_ID (the remote runner
|
||||
# sets it), ignored with a warning when the registry lacks that job.
|
||||
# `registry.py list --parent <id>` lists a job's direct children.
|
||||
|
||||
# 1b) Same, for an agent on another host (no herdr pane, no shared disk):
|
||||
# the brief travels over the broker as a signed retained dispatch and a
|
||||
@@ -165,6 +170,7 @@ Job lifecycle execution events are persistently mirrored to an append-only log u
|
||||
## Best Practices and Pitfalls
|
||||
|
||||
- **Subscribe-Before-Publish**: The subscriber must be running before the agent starts publishing. The `submit` command handles this automatically by launching the subscriber in the background first.
|
||||
- **Sub-delegation carries `--parent-job` (Issue #34)**: an agent that hands part of its job to another agent must pass `--parent-job <its own job_id>` (the injected instructions and `brief.md` say so). Without it the loop does not wait for the sub-job; reviewers see it only as an unattributed open job. From a git worktree the worktree's copy of this wrapper runs; the pane's `MAM_JOBS_DIR` keeps the registry the same one.
|
||||
- **Fresh job_id Propagation**: Make sure the worker agent receives the correct `JOB_ID` generated for the current run, rather than reusing stale IDs from previous sessions.
|
||||
- **Brief delivery via file path**: For long or complex prompts, write the instructions to a file (e.g. `/tmp/task-brief.md`) and pass a short prompt pointing to the file path to prevent terminal buffer overflows.
|
||||
- **Prompts injected into a live agent session MUST be English, ASCII-only, and short** — this is exactly what `--prompt`/the `instructions` string sent to `run_agent()` end up as. Any Korean (or other non-ASCII) content the task needs to convey must go in a markdown brief file (e.g. `.mam/jobs/<id>/brief.md`, written in Korean is fine) that the injected prompt merely tells the agent to read. Two independent bugs in `send_keys_safe`'s paste-verification (in `lib.sh`) made this matter in practice: (a) its marker was taken with a byte-based `tail -c 24`, which can slice a multi-byte UTF-8 (e.g. Korean) character in half; (b) the rendered pane soft-wraps long lines at the terminal width, which can split the marker across two visual lines. Both are now fixed at the source (character-safe truncation + newline-stripped matching before comparison), but keeping injected prompts short/English/file-referencing is still the cheapest way to avoid ever exercising this edge case at all — it's also simply what `submit`'s own default instruction template already does (see `Core Commands` above).
|
||||
|
||||
@@ -211,12 +211,17 @@ sequenceDiagram
|
||||
| **Diff base** | `--base <ref>` (CLI 전용, env 없음) | 리뷰 diff 의 base 를 고정합니다. 소스 HEAD 의 조상이어야 하며 아니면 exit 1. 생략 시 Phase 2 시작 시점의 소스 HEAD 입니다. |
|
||||
| **Review only** | `--review-only` | Phase 2(구현 위임)를 건너뛰고 `<base>..HEAD` 를 리뷰합니다. `--base` 필수, `--plan` 과 함께 쓸 수 없습니다. 수정·순응 잡은 여전히 creator 에게 갑니다. |
|
||||
| **Review isolation** | `--review-isolation worktree\|env` | `--worktree`/`--base` 에서만 의미. `worktree`(기본): 라운드마다 스냅샷의 detached 리뷰 워크트리(TMPDIR)에서 검증합니다. `env`: 소스 루트에서 `PYTHONDONTWRITEBYTECODE=1 … -p no:cacheprovider --basetemp=<밖>` 지침으로 검증합니다. 리뷰 워크트리를 열 수 없으면 조용히 낮추지 않고 exit 1. `env` 에서 리뷰어가 ignore 되지 않는 산출물을 소스 루트에 남기면 라운드가 stale 로 판정돼 재리뷰가 반복됩니다(fail-closed) — 산출물은 `--basetemp` 등으로 소스 밖에 둡니다. |
|
||||
| **Sub-jobs** | `--wait-open-jobs` | creator 잡의 하위 잡(아래 "하위 위임 잡") 외에, creator 작업 중 `--parent-job` 없이 등록된 열린 잡도 기다립니다. 기본 off: 같은 제어 평면의 무관한 잡이 루프를 붙잡을 수 있기 때문입니다. Python 루프 전용. |
|
||||
| **Remote reviewers** | `--remote-review refuse\|diff-only` | `--worktree`/`--base` 에서만 의미. 원격 리뷰어(`transport: remote`)는 이 호스트의 리뷰 트리에 닿을 수 없으므로 기본으로 **어떤 잡도 위임하기 전에** 거부(exit 1)합니다. `diff-only` 는 스냅샷 SHA 와 diff 만을 근거로 받아들이고 그렇게 기록합니다. |
|
||||
|
||||
`--worktree` 또는 `--base` 가 있으면 매 리뷰 라운드(셀프 리뷰 포함) 전에 소스 루트의 변경분을 git 종료 코드로 판정합니다. 변경분이 비었거나 판정할 수 없으면 리뷰를 요청하지 않고 exit 1 로 끝납니다(fail-closed). 둘 다 없으면 기존 동작 그대로입니다.
|
||||
|
||||
**리뷰 identity (Issue #21 항목 5).** `--worktree`/`--base` 가 있으면 매 리뷰 라운드를 `(loop_id, base, head, tree)` 에 묶습니다. 소스의 미커밋·untracked 상태까지 담은 스냅샷(ref 없는 커밋)을 만들고, 리뷰어가 받는 diff 도 그 스냅샷에서 만듭니다(`base..snapshot`). 라운드가 끝난 뒤 소스가 바뀌었으면 그 라운드의 PASS 는 버리고 수정 잡 없이 다시 리뷰합니다(마지막 반복이면 exit 1). 승격 직전에도 한 번 더 확인하며, 승격된 리포트 옆에 `report-<jid>.identity.json`(loop_id·base·head·tree·스냅샷 커밋·리뷰어·`transport`·`evidence`: `review-tree`/`source-tree`/`diff-only`)을 둡니다. 추적되지 않는 중첩 git 저장소는 스냅샷에 담을 수 없어 거부합니다. 서브모듈 안의 미커밋·untracked 내용도 스냅샷에는 gitlink 커밋만 남으므로 거부합니다(라운드 시작 시 exit 1, 리뷰 중에 생기면 그 라운드는 stale). `submodule.*.ignore` 설정으로 가려지지 않습니다. 리뷰어가 없으면 creator 셀프 리뷰가 같은 리뷰어 경로(스냅샷 diff·증거 검사·승격 직전 재확인·사이드카)를 거치고, NOT PASS 면 수정 잡 없이 다시 리뷰합니다. 리뷰 잡의 `[워크트리 컨텍스트]` 는 검증 대상을 `[리뷰 identity]` 의 검증 경로 하나로만 지시합니다.
|
||||
|
||||
**하위 위임 잡 (Issue #34).** creator 가 작업 일부를 `delegate-job submit --parent-job <자기 job_id>` 로 맡기면, 루프는 creator 잡(실행·수정·순응)이 끝난 뒤 그 잡의 자손(자식·손자…, 폴링마다 다시 읽음)의 레코드가 모두 종결될 때까지 기다린 다음 리뷰로 넘어갑니다. 깊이 제한은 없고 상한은 둘입니다: `MAM_CHILD_WAIT_S`(기본 3900 s, creator 잡 종결부터; 각 하위 잡은 자기 등록 + `timeout_sec`(#33, 기본 3600 s)에 닫히므로 보통 그 전에 끝납니다)와 `MAM_JOB_TREE_MAX`(기본 50 개, 넘으면 기다리지 않음). 그만큼 루프 벽시계가 늘어납니다. 루프를 잡으로 감싸 돌리면 바깥 잡의 3600 s 가 먼저 끝날 수 있습니다. 자식의 결과는 루프를 멈추지 않고 리뷰 근거가 됩니다: 하위 잡이나 귀속되지 않은 열린 잡이 있으면 모든 리뷰 프롬프트(셀프 리뷰 포함) 앞에 `[하위 위임 잡]` 표(상태·사유·깊이)와 `[귀속되지 않은 열린 잡]`(부모 미표기로 이 작업 중 등록된 열린 잡) 줄이 붙고(둘 다 없으면 프롬프트는 전과 같습니다), 리뷰어는 `OPEN`·`CLOSED-UNCONFIRMED`·실패(`error`/`cancelled`/`NOT-DISPATCHED`) 하위 잡이 있으면 creator 리포트가 대체 완료를 입증하지 않는 한 NOT PASS 를 냅니다. `CLOSED-UNCONFIRMED` 는 오케스트레이터가 마감(`deadline_timeout`/`agent_blocked`)으로 닫았거나 사유가 없는 `error` 입니다 — 레코드만 닫혔고 에이전트는 인터럽트되지 않으므로 계속 쓰고 있을 수 있습니다. creator 잡 자체의 실패는 전처럼 exit 1 입니다.
|
||||
|
||||
**리뷰 중 소스 변경 = 승인 무효 (모든 모드, Issue #34).** `--worktree`/`--base` 가 없어도 라운드마다 리뷰 요청 직전 소스(= 제어 루트)의 head 와 미커밋·untracked 를 포함한 tree 를 기록하고, 판정 수집 뒤와 승격 직전에 다시 계산합니다. 바뀌었으면 위 identity 모드와 같이 그 라운드의 PASS 를 버리고 수정 잡 없이 다시 리뷰합니다(마지막 반복이면 exit 1). 제어 평면(`.mam`, 잡·감사 로그 디렉터리)은 비교에서 뺍니다. 리뷰어가 ignore 되지 않는 산출물을 소스에 남기면 라운드가 stale 이 되니 산출물은 소스 밖에 둡니다. git 저장소가 아니거나 서브모듈이 dirty 해 지문을 만들 수 없으면 경고(`stale-review guard is off`) 후 기존 동작입니다. 루프가 끝난 **뒤**의 늦은 쓰기는 막을 수 없으며 다음 루프의 diff 에 미커밋 변경으로 드러납니다.
|
||||
|
||||
구현이 루프 밖(워크트리의 creator 에게 `delegate-job --type direct`)에서 끝났다면, **구현 위임 전에** base 를 기록해 두고 리뷰만 돌립니다:
|
||||
|
||||
```bash
|
||||
|
||||
Reference in new issue
Block a user