fix(agents): pin post-discovered session ids on a verified completed; agy never takes another workspace's or session's conversation (Issue #40)

- BaseAgentAdapter: id_lifecycle (pre_assigned: claude, grok / post_discovered)
  and capture_active_session_id - exactly one verified candidate newer than the
  session that no other row records, else a reason (no-candidate, ambiguous, ...).
- agy: verify_artifact (discover) rejects an id last_conversations.json maps to
  another workspace and always excludes ids other rows record (a cache hit no
  longer bypasses it). capture uses the cache only as a proposal: the
  conversation's presence lock or DB must be held by the row's pane process or
  a descendant (lsof/ps); anything unprovable is not pinned.
- lib_py/agents/autopin.py: handle_completed, run by the side that verified the
  job's completed - the delegate-job wrapper (direct), create --onboard and the
  loop's wait_for_job (recovery, as a subprocess: G9). Local herdr jobs only;
  one (job, dispatch token, attempt) is handled once (job-scoped flock + marker
  in the job dir); writes go through atomic_dump_yaml; a pin records
  session_id_source=discovered / session_id_verified=true; a failure leaves the
  reason on the row and never changes the job's result.
- reconcile.sh drift C for agy, hermes, opencode and codex calls the same
  capture (the agy *.db glob is gone); _pin_and_verify_resume uses pin_row.
- Tests: tests/test_issue40_auto_pin.py; issue64 :407 now expects False; the
  static reconcile-source checks follow the move to the adapters; the two tier2
  drift-C component tests create with --no-onboard (onboarding now pins).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
GodopuandClaude Opus 5.5 committed 2026-10-20 23:40:03 +09:00
1 parent ff8b381520
commit feccfd5e03
19 files changed
+1128 -338

No files matched your search

@@ -220,6 +220,7 @@ bash .agents/skills/multi-agent-mux-create/scripts/worktree_prepare.sh \
- **Don't use `nohup`/`disown`/`setsid` for the agent itself** — those background the agent outside herdr. The whole point of this skill is *the herdr session is the supervisor*. `nohup` is OK only for *launching the wrapper* (which itself creates the herdr session via `herdr new-session -d`).
- **Claude Session ID Auto-Assignment**: Fresh `claude` sessions automatically generate a new UUID (`mam_gen_uuid`) passed via `claude --session-id <uuid>`. `claude_session_id_own` is stored in `.mam/agent-sessions.yaml` with `session_id_source: assigned` and `session_id_verified: false`.
- **First Message Materialization**: The transcript file `.jsonl` is created on disk when the first user prompt is sent. The monitor loop (`reconcile.sh`) verifies the transcript and promotes `session_id_verified: true` and `last_visible_status: pinned`.
- **Post-discovered ids (agy, hermes, opencode, codex)**: these rows start with no id (`session_id_source: pending-discovery`). With `--onboard`, create pins the id itself once the onboarding job completes (Issue #40, `lib_py.agents.autopin`), monitor or not; later, every completed delegate job does the same until the id is set.
- **Wrapper script MUST NOT be created via `hermes profile alias`** — that command writes a `hermes -p <profile>` wrapper that destroys the herdr behavior. Create wrappers manually (see `lab-landing-page-creator-claude` template).
- **Always use the workspace-relative path** in herdr `cwd` — relative paths break when herdr respawns in a different shell context.
@@ -751,6 +751,9 @@ If you delegate any part of it with multi-agent-mux-delegate-job submit, add --p
case "$ONBOARD_STATUS" in
completed)
echo "onboarding completed: job $DELEGATE_JOB_ID ($(( $(date +%s) - ONBOARD_T0 ))s)"
# Issue #40: the first turn is done, so a post-discovered id is on disk -
# pin it now instead of waiting for a monitor (worktree creators run none).
delegate_autopin_completed "$DELEGATE_JOB_ID" "$DELEGATE_JOB_TOKEN" "$task_reg_dir"
;;
*)
# The session is kept, as for a missing handshake above: the row says