From 29d7c09340f0daec3f7bdaffd521fdbd969553c5 Mon Sep 17 00:00:00 2001 From: JamesWU Date: Sat, 4 Jul 2026 16:52:49 -0700 Subject: [PATCH 1/8] fix(spawn): compare physical paths in treehouse wait loop for symlinked projects The wait loop after 'treehouse get' polled the pane's PHYSICAL cwd but compared it against the logically-resolved PROJ_ABS. Through a symlinked projects/ the two differ from the first poll, so the loop broke before treehouse created the worktree, captured the project checkout as WT, and the isolation guard refused the launch. Keep waiting while the pane matches either the logical or physical project path. Regression test drives fm-spawn through a symlinked project dir with a stateful fake tmux whose first polls report the project's physical cwd. --- bin/fm-spawn.sh | 7 ++- tests/fm-spawn-symlink-wait.test.sh | 94 +++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100755 tests/fm-spawn-symlink-wait.test.sh diff --git a/bin/fm-spawn.sh b/bin/fm-spawn.sh index bd760060..fd4d1484 100755 --- a/bin/fm-spawn.sh +++ b/bin/fm-spawn.sh @@ -789,9 +789,14 @@ if [ "$KIND" != secondmate ] && [ "$BACKEND" != orca ]; then spawn_send_text_line "$T" 'treehouse get' # Wait for the treehouse subshell: the pane's cwd moves from the project to the worktree. + # Backends report the pane's PHYSICAL cwd, while PROJ_ABS is logical; through a + # symlinked projects/ the two differ from the very first poll, which would + # break the loop before treehouse moves the pane and capture the primary checkout + # as WT. Compare against both forms so the loop waits until the pane really moves. + PROJ_PHYS=$(cd "$PROJ_ABS" && pwd -P) for _ in $(seq 1 60); do p=$(spawn_current_path "$T" || true) - if [ -n "$p" ] && [ "$p" != "$PROJ_ABS" ]; then + if [ -n "$p" ] && [ "$p" != "$PROJ_ABS" ] && [ "$p" != "$PROJ_PHYS" ]; then WT="$p" break fi diff --git a/tests/fm-spawn-symlink-wait.test.sh b/tests/fm-spawn-symlink-wait.test.sh new file mode 100755 index 00000000..528ed34a --- /dev/null +++ b/tests/fm-spawn-symlink-wait.test.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +# Behavior test for fm-spawn.sh's treehouse wait loop through a SYMLINKED +# project dir. +# +# Backends report the pane's PHYSICAL cwd, but PROJ_ABS is resolved with a +# logical pwd. Through a symlinked projects/, physical != logical from +# the very first poll, so the old break condition (`p != PROJ_ABS`) fired +# before treehouse moved the pane, captured the project checkout as WT, and +# the isolation guard refused the launch. The fake tmux here returns the +# project's physical path for the first polls and the worktree afterwards, +# so the loop must keep waiting through the symlink mismatch to succeed. +set -u + +# shellcheck source=tests/lib.sh +. "$(dirname "${BASH_SOURCE[0]}")/lib.sh" + +SPAWN="$ROOT/bin/fm-spawn.sh" +TMP_ROOT=$(fm_test_tmproot fm-spawn-symlink-wait) + +# Fake tmux whose pane-path query is stateful: calls 1..FM_FAKE_PANE_MOVE_AFTER +# return FM_FAKE_PANE_PATH_BEFORE (the pane still sitting in the project), +# later calls return FM_FAKE_PANE_PATH (treehouse moved it to the worktree). +make_symlink_spawn_fakebin() { + local dir=$1 fakebin + fakebin=$(fm_fakebin "$dir") + cat > "$fakebin/tmux" <<'SH' +#!/usr/bin/env bash +set -u +case "$*" in + *"#{pane_current_path}"*) + n=0 + if [ -n "${FM_FAKE_PANE_COUNT:-}" ] && [ -f "$FM_FAKE_PANE_COUNT" ]; then + n=$(cat "$FM_FAKE_PANE_COUNT") + fi + n=$((n + 1)) + [ -z "${FM_FAKE_PANE_COUNT:-}" ] || printf '%s\n' "$n" > "$FM_FAKE_PANE_COUNT" + if [ "$n" -le "${FM_FAKE_PANE_MOVE_AFTER:-0}" ]; then + printf '%s\n' "${FM_FAKE_PANE_PATH_BEFORE:-}" + else + printf '%s\n' "${FM_FAKE_PANE_PATH:-}" + fi + exit 0 + ;; +esac +case "${1:-}" in + display-message) printf 'firstmate\n'; exit 0 ;; + list-windows) exit 0 ;; + has-session|new-session|new-window|kill-window) exit 0 ;; + send-keys) exit 0 ;; +esac +exit 0 +SH + chmod +x "$fakebin/tmux" + fm_fake_exit0 "$fakebin" treehouse + printf '%s\n' "$fakebin" +} + +test_symlinked_project_waits_for_worktree_move() { + local id case_dir home proj proj_link proj_phys wt fakebin count out status + id=symlink-wait-z1 + case_dir="$TMP_ROOT/symlink-wait" + home="$case_dir/home" + proj="$case_dir/project" + proj_link="$case_dir/project-link" + wt="$case_dir/wt" + count="$case_dir/pane-count" + fakebin=$(make_symlink_spawn_fakebin "$case_dir/fake") + mkdir -p "$home/data/$id" "$home/projects" "$home/state" "$home/config" + printf 'claude\n' > "$home/config/crew-harness" + printf 'brief for %s\n' "$id" > "$home/data/$id/brief.md" + touch "$home/state/.last-watcher-beat" + fm_git_worktree "$proj" "$wt" "wt-$id" + ln -s "$proj" "$proj_link" + proj_phys=$(cd "$proj" && pwd -P) + + out=$(FM_ROOT_OVERRIDE='' FM_HOME="$home" \ + FM_STATE_OVERRIDE="$home/state" FM_DATA_OVERRIDE="$home/data" \ + FM_PROJECTS_OVERRIDE="$home/projects" FM_CONFIG_OVERRIDE="$home/config" \ + FM_SPAWN_NO_GUARD=1 TMUX="fake,1,0" PATH="$fakebin:$PATH" \ + FM_FAKE_PANE_COUNT="$count" FM_FAKE_PANE_MOVE_AFTER=2 \ + FM_FAKE_PANE_PATH_BEFORE="$proj_phys" FM_FAKE_PANE_PATH="$wt" \ + "$SPAWN" "$id" "$proj_link" 2>&1) + status=$? + expect_code 0 "$status" "spawn through a symlinked project dir should wait out the pane's physical-cwd polls and succeed" + assert_not_contains "$out" "did not yield an isolated worktree" \ + "spawn treated the pane's physical project cwd as the worktree move" + assert_contains "$out" "worktree=$wt" "spawn did not capture the real worktree path" + assert_grep "worktree=$wt" "$home/state/$id.meta" "meta did not record the real worktree" + pass "wait loop keeps polling while a symlinked project's pane reports its physical cwd" +} + +test_symlinked_project_waits_for_worktree_move + +echo "# all fm-spawn-symlink-wait tests passed" From 8cfac8087a030948ea812ce37c341c6e7a3919fe Mon Sep 17 00:00:00 2001 From: JamesWU Date: Sun, 5 Jul 2026 15:15:30 -0700 Subject: [PATCH 2/8] no-mistakes(document): document spawn symlink wait fix and new regression test --- .omc/project-memory.json | 117 ++++++++++++++++++ .../7f17c099-4eb3-4bce-9b61-817599c8deea.json | 8 ++ .../fd2f88f4-45cc-47d6-87f3-70c52b90bb46.json | 8 ++ CONTRIBUTING.md | 1 + docs/herdr-backend.md | 6 +- 5 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 .omc/project-memory.json create mode 100644 .omc/sessions/7f17c099-4eb3-4bce-9b61-817599c8deea.json create mode 100644 .omc/sessions/fd2f88f4-45cc-47d6-87f3-70c52b90bb46.json diff --git a/.omc/project-memory.json b/.omc/project-memory.json new file mode 100644 index 00000000..bb09a03f --- /dev/null +++ b/.omc/project-memory.json @@ -0,0 +1,117 @@ +{ + "version": "1.0.0", + "lastScanned": 1783289009027, + "projectRoot": "/Users/jamesww/.no-mistakes/worktrees/08e424258b59/01KWT4XHX8HB07F8NK3Y4PY5T8", + "techStack": { + "languages": [], + "frameworks": [], + "packageManager": null, + "runtime": null + }, + "build": { + "buildCommand": null, + "testCommand": null, + "lintCommand": null, + "devCommand": null, + "scripts": {} + }, + "conventions": { + "namingStyle": null, + "importStyle": null, + "testPattern": null, + "fileOrganization": null + }, + "structure": { + "isMonorepo": false, + "workspaces": [], + "mainDirectories": [ + "assets", + "bin", + "docs", + "tests" + ], + "gitBranches": null + }, + "customNotes": [], + "directoryMap": { + "assets": { + "path": "assets", + "purpose": "Static assets", + "fileCount": 1, + "lastAccessed": 1783289009009, + "keyFiles": [ + "banner.png" + ] + }, + "bin": { + "path": "bin", + "purpose": "Executable scripts", + "fileCount": 45, + "lastAccessed": 1783289009009, + "keyFiles": [ + "fm-backend-hometag-lib.sh", + "fm-backend.sh", + "fm-backlog-handoff.sh", + "fm-bootstrap.sh", + "fm-brief.sh" + ] + }, + "docs": { + "path": "docs", + "purpose": "Documentation", + "fileCount": 9, + "lastAccessed": 1783289009010, + "keyFiles": [ + "architecture.md", + "cmux-backend.md", + "configuration.md", + "herdr-backend.md", + "orca-backend.md" + ] + }, + "skills": { + "path": "skills", + "purpose": null, + "fileCount": 0, + "lastAccessed": 1783289009010, + "keyFiles": [] + }, + "tests": { + "path": "tests", + "purpose": "Test files", + "fileCount": 51, + "lastAccessed": 1783289009010, + "keyFiles": [ + "cmux-test-safety.sh", + "fm-afk-inject-e2e.test.sh", + "fm-afk-inject-herdr-e2e.test.sh", + "fm-backend-autodetect-smoke.test.sh", + "fm-backend-cmux-smoke.test.sh" + ] + }, + "docs/examples": { + "path": "docs/examples", + "purpose": "Example code", + "fileCount": 1, + "lastAccessed": 1783289009011, + "keyFiles": [ + "crew-dispatch.json" + ] + } + }, + "hotPaths": [ + { + "path": "docs/herdr-backend.md", + "accessCount": 3, + "lastAccessed": 1783289684726, + "type": "file" + }, + { + "path": "CONTRIBUTING.md", + "accessCount": 2, + "lastAccessed": 1783289630227, + "type": "file" + } + ], + "userDirectives": [] +} \ No newline at end of file diff --git a/.omc/sessions/7f17c099-4eb3-4bce-9b61-817599c8deea.json b/.omc/sessions/7f17c099-4eb3-4bce-9b61-817599c8deea.json new file mode 100644 index 00000000..28e40191 --- /dev/null +++ b/.omc/sessions/7f17c099-4eb3-4bce-9b61-817599c8deea.json @@ -0,0 +1,8 @@ +{ + "session_id": "7f17c099-4eb3-4bce-9b61-817599c8deea", + "ended_at": "2026-07-05T22:05:19.044Z", + "reason": "other", + "agents_spawned": 0, + "agents_completed": 0, + "modes_used": [] +} \ No newline at end of file diff --git a/.omc/sessions/fd2f88f4-45cc-47d6-87f3-70c52b90bb46.json b/.omc/sessions/fd2f88f4-45cc-47d6-87f3-70c52b90bb46.json new file mode 100644 index 00000000..a901afd8 --- /dev/null +++ b/.omc/sessions/fd2f88f4-45cc-47d6-87f3-70c52b90bb46.json @@ -0,0 +1,8 @@ +{ + "session_id": "fd2f88f4-45cc-47d6-87f3-70c52b90bb46", + "ended_at": "2026-07-05T22:15:29.808Z", + "reason": "other", + "agents_spawned": 0, + "agents_completed": 0, + "modes_used": [] +} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e066fa8..fd743020 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,6 +91,7 @@ tests/fm-tangle-guard.test.sh # primary-checkout tangle detection, r tests/fm-brief.test.sh # fm-brief.sh bash -n parse regression guard (issue #166) and clean no-mistakes/direct-PR/local-only brief generation tests tests/fm-spawn-batch.test.sh # batch dispatch and FM_HOME project-path scoping tests tests/fm-spawn-dispatch-profile.test.sh # concrete dispatch profile flags: active-profile backstop, harness/model/effort meta, launch templates, batch forwarding, and secondmate exemption +tests/fm-spawn-symlink-wait.test.sh # treehouse wait loop keeps polling through a symlinked project's physical-vs-logical pane-path mismatch instead of capturing the primary checkout as the worktree tests/fm-update.test.sh # fast-forward-only self-update, reread, nudge, dedup, and skip-safety tests tests/fm-secondmate-sync.test.sh # local-HEAD secondmate sync, no-fetch, bootstrap nudge gating, and spawn hook tests tests/fm-secondmate-harness.test.sh # secondmate-vs-crewmate harness resolution, optional secondmate model/effort pins, primary-to-secondmate config inheritance, and config-push tests diff --git a/docs/herdr-backend.md b/docs/herdr-backend.md index 21645fc3..6f23cdd7 100644 --- a/docs/herdr-backend.md +++ b/docs/herdr-backend.md @@ -35,7 +35,7 @@ You do not need to attach for routine supervision: `bin/fm-peek.sh fm-` read Verify it works by spawning a trivial task with `--backend herdr` and confirming the task's meta records `backend=herdr` plus `herdr_session=`, `herdr_workspace_id=`, `herdr_tab_id=`, and `herdr_pane_id=`; the workspace for your home should show the new `fm-` tab. -Limitations: herdr is experimental, not yet used for `bin/fm-bootstrap.sh`'s required-tools list (the version/tool gate happens at spawn time instead), and carries the known gaps documented below (a small-`--lines` capture bug with a built-in workaround, and a `pane_cwd`-adjacent worktree-discovery symlink fragility) - see "Known gaps and follow-up notes" at the end of this document. +Limitations: herdr is experimental, not yet used for `bin/fm-bootstrap.sh`'s required-tools list (the version/tool gate happens at spawn time instead), and carries the known gaps documented below (a small-`--lines` capture bug with a built-in workaround) - see "Known gaps and follow-up notes" at the end of this document. ## Status: experimental @@ -377,8 +377,8 @@ This is a test-harness-only concern - `fm_backend_herdr_composer_state` and `fm_ A genuine `events.subscribe`-driven push is a reasonable follow-up, not implemented here. - **`bin/fm-bootstrap.sh`'s required-tools list is unchanged.** It still unconditionally requires `tmux`, and does not yet conditionally add `herdr` and `jq` when a backend selection resolves to herdr. The version/tool gate happens at spawn time instead and refuses loudly, so this is bootstrap-detection polish, not a functional gap. -- **Worktree-discovery isolation guard is symlink-fragile for a project path under a symlinked prefix (e.g. macOS's `/tmp` -> `/private/tmp`).** Discovered while building the runtime-backend-auto-detection real smoke test (`tests/fm-backend-autodetect-smoke.test.sh`), which needed a scratch project. `fm-spawn.sh`'s `PROJ_ABS` is a LOGICAL `cd && pwd` (symlink components kept), while herdr's `foreground_cwd` (and real tmux's `pane_current_path`, on the same OS-level cwd primitive) report the PHYSICALLY resolved path. - When the project itself lives under a symlinked directory, the very first worktree-discovery poll sees two different strings for the identical starting directory and the isolation guard false-refuses the spawn as "not isolated" before `treehouse get` ever moves the pane - backend-agnostic, not specific to herdr. Worked around in the test by resolving its scratch `TMP_ROOT` through `pwd -P` before use; the underlying `fm-spawn.sh` path-comparison gap (worth resolving `PROJ_ABS` physically, or comparing physically-resolved forms in the isolation guard) is unfixed and worth a dedicated follow-up. +- **RESOLVED: worktree discovery is no longer symlink-fragile for a project path under a symlinked prefix (e.g. macOS's `/tmp` -> `/private/tmp`).** Discovered while building the runtime-backend-auto-detection real smoke test (`tests/fm-backend-autodetect-smoke.test.sh`), which needed a scratch project. `fm-spawn.sh`'s `PROJ_ABS` is a LOGICAL `cd && pwd` (symlink components kept), while herdr's `foreground_cwd` (and real tmux's `pane_current_path`, on the same OS-level cwd primitive) report the PHYSICALLY resolved path. + When the project itself lived under a symlinked directory, the very first worktree-discovery poll saw two different strings for the identical starting directory, broke the wait loop before `treehouse get` ever moved the pane, captured the project checkout as the worktree, and the isolation guard false-refused the spawn as "not isolated" - backend-agnostic, not specific to herdr. Fixed in `fm-spawn.sh`'s wait loop, which now also resolves the project path physically (`pwd -P`) and keeps polling until the pane's path differs from both the logical and physical forms; regression-covered by `tests/fm-spawn-symlink-wait.test.sh`. (`tests/fm-backend-autodetect-smoke.test.sh` still resolves its scratch `TMP_ROOT` through `pwd -P` before use, which is now belt-and-suspenders rather than load-bearing.) - **RESOLVED: a restart's restored-layout husk no longer needs a manual pane close before respawn.** See "Respawn idempotency: a restored task tab is a husk, not a duplicate" above for the fix (`fm_backend_herdr_pane_agent_state`, `fm_backend_herdr_create_task`'s close-and-replace). Left over from that fix: the `dead` (`pane_not_found`) husk classification is exercised only at the unit level, never against the real binary - killing a pane's process on a live server was observed to make herdr reap the whole tab immediately (never leaving a dead-but-still-listed pane for the duplicate check to find), and a real session restart was never observed to produce one either. It remains a conservative, defensively-coded path for a herdr failure mode (e.g. a restored process that fails to start) nobody has reproduced against the real binary yet. From 64dffd2d1b90afecb7a631581dc95ff980b356c3 Mon Sep 17 00:00:00 2001 From: JamesWU Date: Sun, 5 Jul 2026 15:29:17 -0700 Subject: [PATCH 3/8] no-mistakes(document): add fm-gotmp test to CONTRIBUTING test list --- .omc/project-memory.json | 12 ++++++------ .../5afa19dd-c894-4056-9ed5-3d92bb55614e.json | 8 ++++++++ CONTRIBUTING.md | 1 + 3 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 .omc/sessions/5afa19dd-c894-4056-9ed5-3d92bb55614e.json diff --git a/.omc/project-memory.json b/.omc/project-memory.json index bb09a03f..ba5d8b61 100644 --- a/.omc/project-memory.json +++ b/.omc/project-memory.json @@ -101,15 +101,15 @@ }, "hotPaths": [ { - "path": "docs/herdr-backend.md", - "accessCount": 3, - "lastAccessed": 1783289684726, + "path": "CONTRIBUTING.md", + "accessCount": 4, + "lastAccessed": 1783290530298, "type": "file" }, { - "path": "CONTRIBUTING.md", - "accessCount": 2, - "lastAccessed": 1783289630227, + "path": "docs/herdr-backend.md", + "accessCount": 3, + "lastAccessed": 1783289684726, "type": "file" } ], diff --git a/.omc/sessions/5afa19dd-c894-4056-9ed5-3d92bb55614e.json b/.omc/sessions/5afa19dd-c894-4056-9ed5-3d92bb55614e.json new file mode 100644 index 00000000..6e1b530d --- /dev/null +++ b/.omc/sessions/5afa19dd-c894-4056-9ed5-3d92bb55614e.json @@ -0,0 +1,8 @@ +{ + "session_id": "5afa19dd-c894-4056-9ed5-3d92bb55614e", + "ended_at": "2026-07-05T22:29:17.091Z", + "reason": "other", + "agents_spawned": 0, + "agents_completed": 0, + "modes_used": [] +} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fd743020..3399d139 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -92,6 +92,7 @@ tests/fm-brief.test.sh # fm-brief.sh bash -n parse regression tests/fm-spawn-batch.test.sh # batch dispatch and FM_HOME project-path scoping tests tests/fm-spawn-dispatch-profile.test.sh # concrete dispatch profile flags: active-profile backstop, harness/model/effort meta, launch templates, batch forwarding, and secondmate exemption tests/fm-spawn-symlink-wait.test.sh # treehouse wait loop keeps polling through a symlinked project's physical-vs-logical pane-path mismatch instead of capturing the primary checkout as the worktree +tests/fm-gotmp.test.sh # per-task GOTMPDIR temp root: fm-spawn's /tmp/fm-/gotmp export and tasktmp= meta, and fm-teardown's tasktmp= cleanup tests/fm-update.test.sh # fast-forward-only self-update, reread, nudge, dedup, and skip-safety tests tests/fm-secondmate-sync.test.sh # local-HEAD secondmate sync, no-fetch, bootstrap nudge gating, and spawn hook tests tests/fm-secondmate-harness.test.sh # secondmate-vs-crewmate harness resolution, optional secondmate model/effort pins, primary-to-secondmate config inheritance, and config-push tests From e46f6c698c305c7ddde9ba3d340d87294aaa3574 Mon Sep 17 00:00:00 2001 From: JamesWU Date: Sun, 5 Jul 2026 15:32:20 -0700 Subject: [PATCH 4/8] no-mistakes(lint): shellcheck and bash syntax checks pass clean --- .omc/sessions/9750a9ca-e9da-4740-934e-9442635560b2.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .omc/sessions/9750a9ca-e9da-4740-934e-9442635560b2.json diff --git a/.omc/sessions/9750a9ca-e9da-4740-934e-9442635560b2.json b/.omc/sessions/9750a9ca-e9da-4740-934e-9442635560b2.json new file mode 100644 index 00000000..b781408b --- /dev/null +++ b/.omc/sessions/9750a9ca-e9da-4740-934e-9442635560b2.json @@ -0,0 +1,8 @@ +{ + "session_id": "9750a9ca-e9da-4740-934e-9442635560b2", + "ended_at": "2026-07-05T22:32:19.990Z", + "reason": "other", + "agents_spawned": 0, + "agents_completed": 0, + "modes_used": [] +} \ No newline at end of file From c1d5a1f8132ac2a580cda0fc4953bce6976e19cd Mon Sep 17 00:00:00 2001 From: JamesWU Date: Sun, 5 Jul 2026 16:25:44 -0700 Subject: [PATCH 5/8] fix(spawn): report a clear error when the project path cannot be physically resolved --- bin/fm-spawn.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/fm-spawn.sh b/bin/fm-spawn.sh index fd4d1484..8283c013 100755 --- a/bin/fm-spawn.sh +++ b/bin/fm-spawn.sh @@ -793,7 +793,10 @@ if [ "$KIND" != secondmate ] && [ "$BACKEND" != orca ]; then # symlinked projects/ the two differ from the very first poll, which would # break the loop before treehouse moves the pane and capture the primary checkout # as WT. Compare against both forms so the loop waits until the pane really moves. - PROJ_PHYS=$(cd "$PROJ_ABS" && pwd -P) + if ! PROJ_PHYS=$(cd "$PROJ_ABS" 2>/dev/null && pwd -P); then + echo "error: cannot resolve physical path of project '$PROJ_ABS'" >&2 + exit 1 + fi for _ in $(seq 1 60); do p=$(spawn_current_path "$T" || true) if [ -n "$p" ] && [ "$p" != "$PROJ_ABS" ] && [ "$p" != "$PROJ_PHYS" ]; then From 6f931f1a71072d7f327c86326c21df54ac6a6827 Mon Sep 17 00:00:00 2001 From: JamesWU Date: Sun, 5 Jul 2026 16:26:03 -0700 Subject: [PATCH 6/8] no-mistakes: apply CI fixes --- .omc/sessions/04f4fba6-2651-4196-859b-cfe36f32dafb.json | 8 ++++++++ .omc/sessions/9c3ac52d-ef0f-40cd-8c0c-58ca228933b4.json | 8 ++++++++ 2 files changed, 16 insertions(+) create mode 100644 .omc/sessions/04f4fba6-2651-4196-859b-cfe36f32dafb.json create mode 100644 .omc/sessions/9c3ac52d-ef0f-40cd-8c0c-58ca228933b4.json diff --git a/.omc/sessions/04f4fba6-2651-4196-859b-cfe36f32dafb.json b/.omc/sessions/04f4fba6-2651-4196-859b-cfe36f32dafb.json new file mode 100644 index 00000000..f004b199 --- /dev/null +++ b/.omc/sessions/04f4fba6-2651-4196-859b-cfe36f32dafb.json @@ -0,0 +1,8 @@ +{ + "session_id": "04f4fba6-2651-4196-859b-cfe36f32dafb", + "ended_at": "2026-07-05T23:26:02.613Z", + "reason": "other", + "agents_spawned": 0, + "agents_completed": 0, + "modes_used": [] +} \ No newline at end of file diff --git a/.omc/sessions/9c3ac52d-ef0f-40cd-8c0c-58ca228933b4.json b/.omc/sessions/9c3ac52d-ef0f-40cd-8c0c-58ca228933b4.json new file mode 100644 index 00000000..b2de61d9 --- /dev/null +++ b/.omc/sessions/9c3ac52d-ef0f-40cd-8c0c-58ca228933b4.json @@ -0,0 +1,8 @@ +{ + "session_id": "9c3ac52d-ef0f-40cd-8c0c-58ca228933b4", + "ended_at": "2026-07-05T22:32:47.683Z", + "reason": "other", + "agents_spawned": 0, + "agents_completed": 0, + "modes_used": [] +} \ No newline at end of file From 74d413290e2d2bc0d9ee904acdeedbe5fa11f0a2 Mon Sep 17 00:00:00 2001 From: JamesWU Date: Sun, 5 Jul 2026 17:23:07 -0700 Subject: [PATCH 7/8] chore: untrack local .omc state files and gitignore .omc/ --- .gitignore | 1 + .omc/project-memory.json | 117 ------------------ .../04f4fba6-2651-4196-859b-cfe36f32dafb.json | 8 -- .../5afa19dd-c894-4056-9ed5-3d92bb55614e.json | 8 -- .../7f17c099-4eb3-4bce-9b61-817599c8deea.json | 8 -- .../9750a9ca-e9da-4740-934e-9442635560b2.json | 8 -- .../9c3ac52d-ef0f-40cd-8c0c-58ca228933b4.json | 8 -- .../fd2f88f4-45cc-47d6-87f3-70c52b90bb46.json | 8 -- 8 files changed, 1 insertion(+), 165 deletions(-) delete mode 100644 .omc/project-memory.json delete mode 100644 .omc/sessions/04f4fba6-2651-4196-859b-cfe36f32dafb.json delete mode 100644 .omc/sessions/5afa19dd-c894-4056-9ed5-3d92bb55614e.json delete mode 100644 .omc/sessions/7f17c099-4eb3-4bce-9b61-817599c8deea.json delete mode 100644 .omc/sessions/9750a9ca-e9da-4740-934e-9442635560b2.json delete mode 100644 .omc/sessions/9c3ac52d-ef0f-40cd-8c0c-58ca228933b4.json delete mode 100644 .omc/sessions/fd2f88f4-45cc-47d6-87f3-70c52b90bb46.json diff --git a/.gitignore b/.gitignore index dc785fb8..23cd45a7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ projects/ state/ data/ .no-mistakes/ +.omc/ .lavish/ .DS_Store .env diff --git a/.omc/project-memory.json b/.omc/project-memory.json deleted file mode 100644 index ba5d8b61..00000000 --- a/.omc/project-memory.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "version": "1.0.0", - "lastScanned": 1783289009027, - "projectRoot": "/Users/jamesww/.no-mistakes/worktrees/08e424258b59/01KWT4XHX8HB07F8NK3Y4PY5T8", - "techStack": { - "languages": [], - "frameworks": [], - "packageManager": null, - "runtime": null - }, - "build": { - "buildCommand": null, - "testCommand": null, - "lintCommand": null, - "devCommand": null, - "scripts": {} - }, - "conventions": { - "namingStyle": null, - "importStyle": null, - "testPattern": null, - "fileOrganization": null - }, - "structure": { - "isMonorepo": false, - "workspaces": [], - "mainDirectories": [ - "assets", - "bin", - "docs", - "tests" - ], - "gitBranches": null - }, - "customNotes": [], - "directoryMap": { - "assets": { - "path": "assets", - "purpose": "Static assets", - "fileCount": 1, - "lastAccessed": 1783289009009, - "keyFiles": [ - "banner.png" - ] - }, - "bin": { - "path": "bin", - "purpose": "Executable scripts", - "fileCount": 45, - "lastAccessed": 1783289009009, - "keyFiles": [ - "fm-backend-hometag-lib.sh", - "fm-backend.sh", - "fm-backlog-handoff.sh", - "fm-bootstrap.sh", - "fm-brief.sh" - ] - }, - "docs": { - "path": "docs", - "purpose": "Documentation", - "fileCount": 9, - "lastAccessed": 1783289009010, - "keyFiles": [ - "architecture.md", - "cmux-backend.md", - "configuration.md", - "herdr-backend.md", - "orca-backend.md" - ] - }, - "skills": { - "path": "skills", - "purpose": null, - "fileCount": 0, - "lastAccessed": 1783289009010, - "keyFiles": [] - }, - "tests": { - "path": "tests", - "purpose": "Test files", - "fileCount": 51, - "lastAccessed": 1783289009010, - "keyFiles": [ - "cmux-test-safety.sh", - "fm-afk-inject-e2e.test.sh", - "fm-afk-inject-herdr-e2e.test.sh", - "fm-backend-autodetect-smoke.test.sh", - "fm-backend-cmux-smoke.test.sh" - ] - }, - "docs/examples": { - "path": "docs/examples", - "purpose": "Example code", - "fileCount": 1, - "lastAccessed": 1783289009011, - "keyFiles": [ - "crew-dispatch.json" - ] - } - }, - "hotPaths": [ - { - "path": "CONTRIBUTING.md", - "accessCount": 4, - "lastAccessed": 1783290530298, - "type": "file" - }, - { - "path": "docs/herdr-backend.md", - "accessCount": 3, - "lastAccessed": 1783289684726, - "type": "file" - } - ], - "userDirectives": [] -} \ No newline at end of file diff --git a/.omc/sessions/04f4fba6-2651-4196-859b-cfe36f32dafb.json b/.omc/sessions/04f4fba6-2651-4196-859b-cfe36f32dafb.json deleted file mode 100644 index f004b199..00000000 --- a/.omc/sessions/04f4fba6-2651-4196-859b-cfe36f32dafb.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "session_id": "04f4fba6-2651-4196-859b-cfe36f32dafb", - "ended_at": "2026-07-05T23:26:02.613Z", - "reason": "other", - "agents_spawned": 0, - "agents_completed": 0, - "modes_used": [] -} \ No newline at end of file diff --git a/.omc/sessions/5afa19dd-c894-4056-9ed5-3d92bb55614e.json b/.omc/sessions/5afa19dd-c894-4056-9ed5-3d92bb55614e.json deleted file mode 100644 index 6e1b530d..00000000 --- a/.omc/sessions/5afa19dd-c894-4056-9ed5-3d92bb55614e.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "session_id": "5afa19dd-c894-4056-9ed5-3d92bb55614e", - "ended_at": "2026-07-05T22:29:17.091Z", - "reason": "other", - "agents_spawned": 0, - "agents_completed": 0, - "modes_used": [] -} \ No newline at end of file diff --git a/.omc/sessions/7f17c099-4eb3-4bce-9b61-817599c8deea.json b/.omc/sessions/7f17c099-4eb3-4bce-9b61-817599c8deea.json deleted file mode 100644 index 28e40191..00000000 --- a/.omc/sessions/7f17c099-4eb3-4bce-9b61-817599c8deea.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "session_id": "7f17c099-4eb3-4bce-9b61-817599c8deea", - "ended_at": "2026-07-05T22:05:19.044Z", - "reason": "other", - "agents_spawned": 0, - "agents_completed": 0, - "modes_used": [] -} \ No newline at end of file diff --git a/.omc/sessions/9750a9ca-e9da-4740-934e-9442635560b2.json b/.omc/sessions/9750a9ca-e9da-4740-934e-9442635560b2.json deleted file mode 100644 index b781408b..00000000 --- a/.omc/sessions/9750a9ca-e9da-4740-934e-9442635560b2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "session_id": "9750a9ca-e9da-4740-934e-9442635560b2", - "ended_at": "2026-07-05T22:32:19.990Z", - "reason": "other", - "agents_spawned": 0, - "agents_completed": 0, - "modes_used": [] -} \ No newline at end of file diff --git a/.omc/sessions/9c3ac52d-ef0f-40cd-8c0c-58ca228933b4.json b/.omc/sessions/9c3ac52d-ef0f-40cd-8c0c-58ca228933b4.json deleted file mode 100644 index b2de61d9..00000000 --- a/.omc/sessions/9c3ac52d-ef0f-40cd-8c0c-58ca228933b4.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "session_id": "9c3ac52d-ef0f-40cd-8c0c-58ca228933b4", - "ended_at": "2026-07-05T22:32:47.683Z", - "reason": "other", - "agents_spawned": 0, - "agents_completed": 0, - "modes_used": [] -} \ No newline at end of file diff --git a/.omc/sessions/fd2f88f4-45cc-47d6-87f3-70c52b90bb46.json b/.omc/sessions/fd2f88f4-45cc-47d6-87f3-70c52b90bb46.json deleted file mode 100644 index a901afd8..00000000 --- a/.omc/sessions/fd2f88f4-45cc-47d6-87f3-70c52b90bb46.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "session_id": "fd2f88f4-45cc-47d6-87f3-70c52b90bb46", - "ended_at": "2026-07-05T22:15:29.808Z", - "reason": "other", - "agents_spawned": 0, - "agents_completed": 0, - "modes_used": [] -} \ No newline at end of file From 02b6165e1fe21a2f690a6ec352b25bc965398191 Mon Sep 17 00:00:00 2001 From: JamesWU Date: Sun, 5 Jul 2026 17:37:56 -0700 Subject: [PATCH 8/8] no-mistakes(document): sync stale symlink-wait comment in autodetect smoke test --- tests/fm-backend-autodetect-smoke.test.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/fm-backend-autodetect-smoke.test.sh b/tests/fm-backend-autodetect-smoke.test.sh index f538ce75..3840b517 100755 --- a/tests/fm-backend-autodetect-smoke.test.sh +++ b/tests/fm-backend-autodetect-smoke.test.sh @@ -49,9 +49,12 @@ command -v treehouse >/dev/null 2>&1 || { echo "skip: treehouse not found (requi # ${TMPDIR:-/tmp} path: on macOS /tmp is a symlink to /private/tmp, and # fm-spawn.sh's PROJ_ABS uses a logical `cd && pwd` while herdr's own # foreground_cwd reports the OS-resolved physical path. A project rooted on -# the logical side of that symlink makes the very first worktree-discovery -# poll see two different STRINGS for the same directory and trip the -# isolation guard's false-refusal before treehouse ever moves the pane. +# the logical side of that symlink used to make the very first +# worktree-discovery poll see two different STRINGS for the same directory +# and trip the isolation guard's false-refusal before treehouse ever moved +# the pane. fm-spawn.sh's wait loop now compares both the logical and +# physical forms (regression-covered by tests/fm-spawn-symlink-wait.test.sh), +# so this pre-resolution is belt-and-suspenders rather than load-bearing. TMP_ROOT=$(mktemp -d "$(cd "${TMPDIR:-/tmp}" && pwd -P)/fm-backend-autodetect-smoke.XXXXXX") SESSION="fm-autodetect-smoke-$$" export HERDR_SESSION="$SESSION"