Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions bin/fm-remote-home-seed.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#
# Known provisioning failure rolls the registry back. SSH status 255 preserves
# the route and any newly scaffolded brief because completion is unknown and a same-route rerun converges.
# The remote charter copy replaces the parent's local parent-channel and steering-inbox paths with the remote home paths the route actually uses.
set -eu

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
Expand Down Expand Up @@ -147,11 +148,18 @@ REG_EXISTED=0
[ -f "$REG" ] && { cp "$REG" "$TMP/registry.before"; REG_EXISTED=1; }

# Keep the parent charter as its durable source, but publish a remote copy whose
# status path is the remote append-only relay log rather than a local Mac path.
# parent-channel and steering-inbox paths are remote-home paths rather than local
# parent-home paths. The steering-inbox path below has to stay the exact inbox
# bin/fm-remote-secondmate-control.sh's cmd_send writes records into and rings
# the doorbell for (its CONTROL_STATE); a charter naming any other path leaves
# the mate reading an inbox nothing delivers to.
PARENT_STATUS="$STATE/$ID.status"
REMOTE_STATUS="$REMOTE_HOME/state/parent-replies.status"
PARENT_INBOX="$STATE/$ID.inbox"
REMOTE_INBOX="$REMOTE_HOME/state/parent-route/$ID.inbox"
while IFS= read -r line || [ -n "$line" ]; do
printf '%s\n' "${line//"$PARENT_STATUS"/"$REMOTE_STATUS"}"
line=${line//"$PARENT_STATUS"/"$REMOTE_STATUS"}
printf '%s\n' "${line//"$PARENT_INBOX"/"$REMOTE_INBOX"}"
done < "$BRIEF" > "$TMP/charter.remote"

PROJECTS_CSV=
Expand Down
3 changes: 2 additions & 1 deletion docs/remote-secondmates.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ FM_HOME=<primary-home> bin/fm-send.sh fm-<id> '<request>'
```

The [`fm-send.sh` header](../bin/fm-send.sh) owns the exact delivery-status contract.
A routed request is delivered as a durable record in the remote home's steering inbox plus a best-effort doorbell, never by typing the payload into the pane; exit 0 means the record durably exists.
A routed request is delivered as a durable record in the remote home's `state/parent-route/<id>.inbox` steering inbox plus a best-effort doorbell, never by typing the payload into the pane; exit 0 means the record durably exists.
The seeded remote charter names that same host-local inbox, so the mate acts on the record the doorbell rang for instead of an unreachable inbox path in the parent's home; re-running `fm-remote-home-seed.sh` republishes that charter into an existing home.
Every remote transport attempt is bounded by `FM_SEND_REMOTE_BUDGET`; that header owns the setting's default and validation contract.
An unconfirmed SSH transport (exit 255) is retried identically once, while a budget expiry is not retried because completion is unknown; either outcome preserves this ordinary reply-bearing request's pending-reply expectation for the record that may have landed.
If delivery remains unconfirmed, only the exact `FM_PENDING_REPLY_EXISTING_CORR=<id>` resend command printed by `fm-send` is safe to run later because it preserves the request body and lets the remote enqueue deduplicate onto the same record; a plain rerun mints a different correlation and is not idempotent.
Expand Down
17 changes: 17 additions & 0 deletions tests/fm-remote-secondmate-lifecycle-e2e.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,23 @@ assert_present "$REMOTE_HOME/.fm-secondmate-home" "remote provisioning did not p
assert_present "$REMOTE_HOME/projects/alpha/.git" "remote provisioning did not clone the project on that host"
assert_grep "$REMOTE_HOME/state/parent-replies.status" "$REMOTE_HOME/data/charter.md" "remote charter did not use its append-only reply log"
assert_no_grep "$PARENT/state/ios.status" "$REMOTE_HOME/data/charter.md" "remote charter retained the inaccessible local status path"
assert_grep "$REMOTE_HOME/state/parent-route/ios.inbox" "$REMOTE_HOME/data/charter.md" "remote charter did not use its host-local steering inbox"
assert_no_grep "$PARENT/state/ios.inbox" "$REMOTE_HOME/data/charter.md" "remote charter retained the inaccessible local steering inbox"
# A home seeded before the charter carried its host-local steering inbox is
# corrected by reseeding the same route, not by patching the home.
remote_inbox_line=$(grep -F "$REMOTE_HOME/state/parent-route/ios.inbox" "$REMOTE_HOME/data/charter.md" | head -n 1)
old_inbox_line=${remote_inbox_line//"$REMOTE_HOME/state/parent-route/ios.inbox"/"$PARENT/state/ios.inbox"}
while IFS= read -r line || [ -n "$line" ]; do
printf '%s\n' "${line//"$REMOTE_HOME/state/parent-route/ios.inbox"/"$PARENT/state/ios.inbox"}"
done < "$REMOTE_HOME/data/charter.md" > "$TMP_ROOT/charter.old-seed"
cp "$TMP_ROOT/charter.old-seed" "$REMOTE_HOME/data/charter.md"
assert_grep "$old_inbox_line" "$REMOTE_HOME/data/charter.md" "the old-seed fixture did not restore the parent steering inbox"
FM_SECONDMATE_CHARTER='Own iOS delivery on the build Mac.' \
FM_SECONDMATE_SCOPE='iOS implementation and Xcode validation' \
remote_env "$ROOT/bin/fm-remote-home-seed.sh" ios remote-mac "$REMOTE_ROOT" "$REMOTE_HOME" alpha >/dev/null \
|| fail "reseeding the existing remote route failed"
assert_grep "$remote_inbox_line" "$REMOTE_HOME/data/charter.md" "reseeding did not republish the host-local steering inbox"
assert_no_grep "$PARENT/state/ios.inbox" "$REMOTE_HOME/data/charter.md" "reseeding kept the old charter's inaccessible steering inbox"
if FM_SECONDMATE_CHARTER='Own iOS delivery on the build Mac.' \
FM_SECONDMATE_SCOPE='iOS implementation and Xcode validation' \
remote_env "$ROOT/bin/fm-remote-home-seed.sh" ios remote-mac "$REMOTE_ROOT" "$TMP_ROOT/other-home" alpha \
Expand Down
Loading