fix(issue-50): review findings of PR #56 on macOS

- admission: a `submit --dry-run` record is marked dry_run and is not an
  open job of its session (review 1e25cf2f F1)
- create: the monitor-row adoption requires the row's server to be the one
  this create spawned on (review 1e25cf2f F2)
- pane lock: retry only on contention (BlockingIOError); the docs say the
  flock lasts while any fd-9 holder (the claim shell and the shim) lives
  (review 66680d9d)
- tests on macOS: real-herdr box HOMEs under /tmp (sun_path is 104 bytes),
  resolved paths, the fake claude reads non-canonical input (MAX_CANON 1024)
  and the pane is read unwrapped; lock holders exec their sleep so killing
  them frees the lock; the adoption tests name the server

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
This commit is contained in:
GodopuandClaude Opus 5.5 committed 2026-10-12 09:03:08 +09:00
1 parent 320aa9f7a0
commit a9ffedac36
10 files changed
+75 -19

No files matched your search

+8 -3
View File
@@ -55,6 +55,9 @@ FAKE_CLAUDE = r'''#!/usr/bin/env bash
if [ "${1:-}" = "auth" ]; then echo '{"loggedIn": true}'; exit 0; fi
printf '\n ▐▛███▛█ Claude Code v2.1.0 (fake)\n▝▜██████▀ Sonnet · Claude Max\n\n'
printf '───────────────────────────────────────────────\n❯ Try "how does <filepath> work?"\n───────────────────────────────────────────────\n ⏵⏵ bypass permissions on (shift+tab to cycle)\n'
# non-canonical input, as a real TUI reads it: a canonical tty line is capped at
# MAX_CANON (1024 bytes on macOS), shorter than one injected prompt
stty -icanon 2>/dev/null
while IFS= read -r line; do printf '\n● got: %s\n❯ \n' "$line"; done
'''
@@ -99,7 +102,7 @@ class Box:
return ""
def pane_text(self, name=SESSION) -> str:
res = self.herdr("agent", "read", name, "--source", "recent")
res = self.herdr("agent", "read", name, "--source", "recent-unwrapped", "--lines", "1000")
try:
d = json.loads(res.stdout)["result"]
return (d.get("read") or d).get("text", "")
@@ -192,7 +195,9 @@ def _row(sess: str, name=SESSION, ws="") -> str:
def _make_box(sess: str) -> Box:
home = Path(tempfile.mkdtemp(prefix="mam50-")) # short: a unix socket path lives under it
# short: a unix socket path lives under it (macOS sun_path is 104 bytes and
# its TMPDIR is long); resolved, as the scripts print /private/tmp paths
home = Path(tempfile.mkdtemp(prefix="mam50-", dir="/tmp")).resolve()
box = Box(home, sess)
for d in (box.bin, box.ws, box.ctl / ".agents", box.jobs, box.ctl / ".mam" / "delegate_job_logs"):
d.mkdir(parents=True)
@@ -382,7 +387,7 @@ def test_c4_the_loops_first_job_waits_for_the_onboarding_to_end(box, monkeypatch
def test_c5_a_session_without_a_row_is_judged_by_the_records_alone(local_mqtt_broker):
# resolve_herdr_session falls back to the workspace slug when the yaml has no
# row, so the server is named exactly that: mam-<parent>-<work> of the control root
home = Path(tempfile.mkdtemp(prefix="mam50-"))
home = Path(tempfile.mkdtemp(prefix="mam50-", dir="/tmp")).resolve()
sess = f"mam-{home.name}-ctl".lower().replace("_", "-")
shutil.rmtree(home)
_TIMERS.clear()