Skip to content
6 changes: 4 additions & 2 deletions bin/fm-crew-state.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@
# branch (branch_sync.state=pipeline_owned), its own custody attribution
# binds an ACTIVE run without head equality (fm_nm_run_is_pipeline_owned_active
# in bin/fm-nm-run-lib.sh).
# A run head whose commit object the task copy never fetched (the pipeline
# committed its fix round in its own checkout) cannot be verified locally;
# A run head the task copy cannot bind - never fetched (the pipeline
# committed its fix round in its own checkout), or resolvable but off this
# worktree's line of history (the pipeline replayed the branch onto an
# advanced upstream) - cannot be verified locally;
# that row is recognized only as a provable pipeline-owned continuation -
# the branch's ACTIVE newest ledger row, anchored by the row immediately
# before it having ended at exactly this worktree's head - so an active fix
Expand Down
70 changes: 43 additions & 27 deletions bin/fm-nm-run-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -166,19 +166,25 @@ fm_nm_run_is_pipeline_owned_active() { # <toon-output>
# row alone decides; older rows are history and never answer for the present:
# - newest row's head resolves and matches the worktree (fm_nm_head_matches_worktree):
# its status word
# - newest row's head resolves but does not match: nothing (a newer run that
# is not this worktree's makes every older row stale history)
# - newest row's head does not resolve in this copy (the pipeline committed
# its fix round in its own checkout and the task copy never fetched it):
# recognized ONLY as a provable pipeline-owned continuation of the
# submitted head, which requires ALL of: the row is ACTIVE (status
# running), and the immediately older row for the SAME branch resolves to
# EXACTLY the worktree HEAD. The pipeline's own ledger then proves an
# unbroken run sequence from a run that ended at the submitted head to an
# active run on the same branch - the anchored active row's status word is
# printed. Anything else (no anchor row, an anchor that is merely an
# ancestor, a terminal unresolvable row) prints nothing, so branch-name
# coincidence, arbitrary remote state, and other tasks' runs never match.
# - newest row's head does not bind - either it does not resolve in this copy
# (the pipeline committed its fix round in its own checkout and the task
# copy never fetched it) or it resolves on a line of history the worktree
# HEAD does not share (the pipeline replayed the branch onto an advanced
# upstream, so neither commit descends from the other):
# a TERMINAL or unclassifiable row prints nothing, because a newer run that
# is not this worktree's makes every older row stale history. An ACTIVE row
# is recognized as a provable pipeline-owned continuation of the submitted
# head, which additionally requires the immediately older row for the SAME
# branch to resolve to EXACTLY the worktree HEAD. The pipeline's own ledger
# then proves an unbroken run sequence from a run that ended at the
# submitted head to an active run on the same branch - the anchored active
# row's status word is printed. Anything else (no anchor row, an anchor
# that is merely an ancestor or merely a descendant) prints nothing, so
# branch-name coincidence, arbitrary remote state, and other tasks' runs
# never match. Both unbindable shapes reach the SAME anchor because a
# rebased head is exactly as unprovable as an unfetched one, and treating
# only the unfetched one that way is what let a dead run report a live
# task as failed (nutrifam-cerrar-allow-authenticated, 2026-09-07).
# The one exception to newest-row-decides is the live-over-terminal rule stated
# with fm_nm_head_matches_worktree above, and it only ever replaces a TERMINAL
# answer with a LIVE one: when the newest row binds but is terminal, the older
Expand All @@ -191,10 +197,11 @@ fm_nm_run_is_pipeline_owned_active() { # <toon-output>
# requires, so branch-name coincidence and other tasks' runs still never
# match. A terminal newest row is the corpse of a crashed attempt whenever a
# live run for the same worktree is still on the ledger, so it is not the
# present. Nothing else widens: a newest row that does not bind still ends the
# scan, a newest row whose class is live or unclassifiable is still answered
# as-is, the anchored pipeline-continuation path is untouched, and with no live
# sibling the newest terminal word is still what is printed.
# present. Nothing else widens: the sibling scan is unchanged, a newest row
# that does not bind still ends the scan unless it is LIVE and its head is
# unprovable rather than superseded, a newest row that binds is still answered
# as-is, the anchor is still exact head equality and nothing else, and with no
# live sibling the newest terminal word is still what is printed.
# Read-only: git reads resolve objects in place; custody never changes.
fm_nm_runs_status_for_worktree() { # <worktree> <branch> <runs-list-output> [expected-head]
local wt=$1 branch=$2 list=$3 expected_head=${4:-}
Expand Down Expand Up @@ -269,19 +276,28 @@ fm_nm_runs_status_for_worktree() { # <worktree> <branch> <runs-list-output> [ex
esac
fi
row_full=$(fm_nm_resolve_commit "$wt" "$sha")
if [ -n "$row_full" ]; then
if fm_nm_head_matches_worktree "$wt" "$sha"; then
decided=$st
# A live or unclassifiable word is this worktree's current answer and
# ends the scan; only a terminal one keeps looking for a live sibling.
if [ "$(fm_nm_run_status_class "$st")" = terminal ]; then
[ "$row_full" != "$local_full" ] || decided_exact=1
continue
fi
if [ -n "$row_full" ] && fm_nm_head_matches_worktree "$wt" "$sha"; then
decided=$st
# A live or unclassifiable word is this worktree's current answer and
# ends the scan; only a terminal one keeps looking for a live sibling.
if [ "$(fm_nm_run_status_class "$st")" = terminal ]; then
[ "$row_full" != "$local_full" ] || decided_exact=1
continue
fi
break
fi
[ "$st" = running ] || break
# The head rule could not bind this row. A head that resolves as a strict
# ANCESTOR of the worktree HEAD is not unprovable, it is superseded: local
# work advanced past it outside the run (the case fm_nm_head_matches_worktree
# rejects on purpose), and no anchor can turn stale history into the present.
if [ -n "$row_full" ] \
&& git -C "$wt" merge-base --is-ancestor "$row_full" "$local_full" 2>/dev/null; then
break
fi
# What remains is genuinely unprovable: a head absent from this copy, or one
# on a line of history the worktree HEAD does not share. Only a LIVE row is
# still recognizable, through the anchor below.
[ "$(fm_nm_run_status_class "$st")" = live ] || break
pending_st=$st
done <<< "$list"
printf '%s' "$decided"
Expand Down
4 changes: 3 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ Any direct or remaining historical annotation prints every status line unread at
For other daemon, timeout, or unreachability claims, a running or fixing run with recent pipeline-reported activity supersedes the event and names reattachment as the recovery instead of surfacing a false block.
[`bin/fm-nm-run-lib.sh`](../bin/fm-nm-run-lib.sh)'s header owns the exact branch, head, pipeline-custody, and newest-first attribution rules.
It also owns which binding run wins when more than one recorded run binds to the same worktree: a live run outranks a terminal one, so a crashed run sitting at the worktree's own commit never reports a healthy task as failed while its live successor is still validating.
A run head the task copy cannot resolve locally is attributed only when the pipeline's own runs ledger proves it is an active continuation of the submitted head, so a pipeline fix round never reads as an older failed run.
A newest run head the task copy cannot bind, whether it never fetched the commit or the pipeline replayed the branch onto an advanced upstream, is attributed only when the pipeline's own runs ledger proves it is an active continuation of the submitted head, so neither a pipeline fix round nor a live run the pipeline rebased ahead of a dead one ever reads as that older failed run.
The live-over-terminal search across older rows stays narrower than that, on the terms the header states.
A run head this copy has already advanced past is superseded local history rather than an unprovable one, so no ledger proof attributes it.
During no-mistakes' `ci` monitor phase, it also reads the ci step log tail because `axi status` reports both "still waiting on checks" and "checks green, waiting on merge" as `ci,running`.
The most recent recognized ci log marker wins, so checks-green monitoring reports done while a later re-arm, failed-check, or issue marker returns the crew to working.
A terminal failed run whose only failure is the ci monitor step, after every substantive step completed and the same marker reads checks green, also reports done with the run's PR URL, because a monitor whose only remaining job is to observe a human merge decision must not convert the absence of that decision into a failure verdict.
Expand Down
Loading
Loading