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
16 changes: 11 additions & 5 deletions bin/fm-spawn.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5509,12 +5509,14 @@ preserve_relaunch_meta() {
echo "home=$PROJ_ABS"
echo "projects=$SECONDMATE_PROJECTS"
fi
if [ "$RELAUNCH" -eq 1 ]; then
preserve_relaunch_meta
fi
# Keep relaunch fields before the preserved PR block so monitoring can parse it;
# fm_pr_metadata_identity_parse owns the allowed fields following pr=.
if [ "$SPAWN_CONTROL_PARENT" = 1 ] && [ -n "${FM_CONTROL_RELAUNCH_TX:-}" ]; then
echo "control_relaunch_tx=$FM_CONTROL_RELAUNCH_TX"
fi
if [ "$RELAUNCH" -eq 1 ]; then
preserve_relaunch_meta
fi
} >"$SPAWN_META_PATH" || {
echo "error: task record for $ID could not be prepared at $SPAWN_META_PATH" >&2
exit 1
Expand Down Expand Up @@ -5863,8 +5865,12 @@ spawn_record_traceparent() {
fi
SPAWN_META_TMP="$STATE/.$ID.meta.trace.${BASHPID:-$$}"
if [ ! -f "$meta" ] || [ ! -w "$meta" ] ||
! awk -F= '$1 != "traceparent"' "$meta" >"$SPAWN_META_TMP" ||
! printf 'traceparent=%s\n' "$SPAWN_TRACEPARENT" >>"$SPAWN_META_TMP" ||
! awk -F= -v carrier="$SPAWN_TRACEPARENT" '
$1 == "traceparent" { next }
$1 == "pr" && !written { print "traceparent=" carrier; written = 1 }
{ print }
END { if (!written) print "traceparent=" carrier }
' "$meta" >"$SPAWN_META_TMP" ||
! fm_backlog_atomic_transition publish "$SPAWN_META_TMP" "$meta" "task record" "$STATE"; then
status=1
rm -f "$SPAWN_META_TMP" 2>/dev/null || true
Expand Down
3 changes: 3 additions & 0 deletions docs/trace-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ Because ambient `TRACEPARENT` is never read, the environment a supervisor happen
Disabling propagation is an intentional trace boundary: a disabled home injects no carrier into a newly launched or relaunched agent even when the task meta already contains a valid `traceparent=`.
An actual disabled relaunch regenerates the task meta without `traceparent=`, so a later enabled relaunch roots a new trace instead of resuming the identity from before the boundary; reusing an already-alive remote endpoint is not a relaunch and preserves the carrier that agent already holds.

Carrier publication removes prior `traceparent=` lines and writes one replacement before the first `pr=` line, or at the end of a record without a PR.
PR monitoring can still parse the preserved identity after relaunch with tracing on or off; [`tests/fm-control-relaunch.test.sh`](../tests/fm-control-relaunch.test.sh)'s `test_relaunch_keeps_a_recorded_pr_parseable_for_monitoring` covers both paths.

### Enablement is home-session-scoped

Each locked `bin/fm-session-start.sh` run resolves that home's `config/trace-context` plus `FM_TRACE_CONTEXT` exactly once into session-scoped effective state.
Expand Down
38 changes: 38 additions & 0 deletions tests/fm-control-relaunch.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,43 @@ test_relaunch_preserves_durable_task_metadata() {
pass "fm-control relaunch: durable task metadata survives replacement launch publication"
}

test_relaunch_keeps_a_recorded_pr_parseable_for_monitoring() {
local dir out rc parsed tracing
for tracing in off on; do
dir=$(new_case "pr-parse-$tracing" rl90)
add_ship_task "$dir" rl90 claude
printf '%s\n' "$$" > "$dir/home/state/.lock"
printf '%s %s\n' "$$" "$tracing" > "$dir/home/state/.trace-context-effective"
{
printf '%s\n' 'traceparent=00-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bbbbbbbbbbbbbbbb-01'
printf '%s\n' 'pr=https://github.com/example/repo/pull/90'
printf '%s\n' 'pr_head=0123456789abcdef0123456789abcdef01234567'
printf '%s\n' 'x_request=request-90'
} >> "$dir/home/state/rl90.meta"

out=$(run_control "$dir" rl90 relaunch --note "keep PR monitoring alive"); rc=$?
expect_code 0 "$rc" "relaunch of a task with a recorded PR and tracing $tracing should succeed"$'\n'"$out"
[ -n "$(meta_field "$dir" rl90 control_relaunch_tx)" ] \
|| fail "the published record should still identify its relaunch transaction"
parsed=$(bash -c '
. "$1/bin/fm-pr-lib.sh"
fm_pr_metadata_identity_parse "$2" && printf "%s\n" "$FM_PR_META_URL"
' _ "$ROOT" "$dir/home/state/rl90.meta")
[ "$parsed" = "https://github.com/example/repo/pull/90" ] \
|| fail "PR monitoring must still parse the relaunched task record with tracing $tracing (got: ${parsed:-rejected})"
if [ "$tracing" = on ]; then
[ "$(awk -F= '$1 == "traceparent" { count++ } END { print count+0 }' "$dir/home/state/rl90.meta")" = 1 ] \
|| fail "traced relaunch must publish exactly one trace carrier"
[ "$(meta_field "$dir" rl90 traceparent)" = "00-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bbbbbbbbbbbbbbbb-01" ] \
|| fail "traced relaunch must preserve the task's recorded carrier"
else
[ -z "$(meta_field "$dir" rl90 traceparent)" ] \
|| fail "untraced relaunch must remove the task's recorded carrier"
fi
pass "fm-control relaunch: a recorded PR stays parseable for PR monitoring with tracing $tracing"
done
}

test_relaunch_serializes_concurrent_durable_metadata_publication() {
local dir control_pid link_pid rc i=0 traceparent prepare launch_release waiting ready release
dir=$(new_case metadata-race rl28)
Expand Down Expand Up @@ -4140,6 +4177,7 @@ test_relaunch_refuses_before_exit_when_the_composer_holds_pending_text
test_relaunch_refuses_before_exit_when_the_composer_state_is_unproven
test_relaunch_from_linked_home_preserves_recorded_worktree
test_relaunch_preserves_durable_task_metadata
test_relaunch_keeps_a_recorded_pr_parseable_for_monitoring
test_relaunch_serializes_concurrent_durable_metadata_publication
test_disabled_relaunch_clears_prior_trace_context
test_relaunch_appends_the_progress_note_to_the_instructions
Expand Down
Loading