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
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ A secondmate's idle endpoint is healthy, and parent supervision relies on its ro
Waiting on a healthy supervision cycle is silent; empty polls, elapsed time, and no-change updates are not captain-facing progress.
Never broadly kill watchers, especially never `pkill -f bin/fm-watch.sh`, because that can kill sibling firstmate homes.
A forced repair must use the home-scoped owner path emitted by supervision instructions.
The same hazard applies to the behavior-test runner, which concurrent agents invoke with near-identical command lines: stop a suite with `bin/fm-test-run.sh --stop [<run-id>]`, never `pkill -f fm-test-run.sh`, and treat a run log carrying neither `FM_TEST_SUMMARY` nor `FM_TEST_ABORTED` as lost output rather than a pass.

Guard warnings do not replace the contract.
Queued wakes must be drained before other action, stale liveness must be repaired through the emitted protocol, and the worktree-tangle warning must be resolved without touching unlanded work.
Expand Down
286 changes: 285 additions & 1 deletion bin/fm-test-run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
# Aggregation (no suite execution):
# fm-test-run.sh --aggregate-json <out.json> <lane.json> [more lane.json...]
#
# Run control (no suite execution):
# fm-test-run.sh --list-runs
# fm-test-run.sh --stop [<run-id>]
#
# Options:
# --json <path> write a deterministic timing artifact after the run
# --list print selected script paths (one per line) and exit 0
Expand All @@ -42,6 +46,15 @@
# selected script is in the proven-isolated set
# (bin/fm-test-isolation-proof.sh --list). Cap is 8. Stateful
# families never schedule under --jobs.
# --list-runs print one FM_TEST_RUN record per registered live run and exit
# --stop [<run-id>]
# stop registered runs by identity, never by process-name
# matching. With a run id, exactly that run. With no run id,
# only the runs registered from THIS repository root, so a
# concurrent agent's suite in another worktree is never a
# candidate. Broad `pkill -f fm-test-run.sh` is what this
# verb exists to replace: concurrent runs share a near
# identical command line, so no pattern can tell them apart.
# -h, --help print this header
#
# Per-script machine-parseable markers (stdout):
Expand All @@ -53,9 +66,22 @@
# FM_TEST_SUMMARY_FAMILY family=<name> count=<n> duration_ms=<n> failed=<n>
# FM_TEST_SLOWEST rank=<k> script=<path> duration_ms=<n>
#
# Instead of that summary, an interrupted run prints exactly one terminator:
# FM_TEST_ABORTED <iso8601> run_id=<id> signal=<name> completed=<n> selected=<n>
# A killed run used to end mid-line, so a truncated log was indistinguishable
# from a short clean one and a reader counting failures off it concluded the
# suite passed. Treat a log with neither FM_TEST_SUMMARY nor FM_TEST_ABORTED as
# lost output, never as a pass.
#
# Exit status is non-zero if any selected script exits non-zero or a configured
# --fail-on-gate-skip token appears. Other gate skips (first meaningful line
# matching ^skip:) remain successful and are counted as skipped_gate.
# An aborted run exits 128+<signal> (143 for TERM, 130 for INT, 129 for HUP).
#
# Every executing run registers itself in a per-user registry directory
# (FM_TEST_RUN_REGISTRY, default $TMPDIR/fm-test-run-registry) and removes that
# record on exit. Records are pruned when their pid is gone, so a crashed run
# leaves no stale entry that a later --stop could act on.
#
# Family labels, the changed-file map, and production portable-shard composition
# live in this script only (one owner). The proven-isolated candidate set remains
Expand Down Expand Up @@ -88,6 +114,19 @@ EXCLUDE_FAMILIES=()
FAIL_ON_GATE_SKIP=
JOBS=1
JOBS_MAX=8
LIST_RUNS=0
STOP_REQUESTED=0
STOP_RUN_ID=

# Where executing runs register their identity so a concurrent agent can stop
# one exactly instead of pattern-matching a shared command line. Per-user by
# default because TMPDIR is per-user on macOS; FM_TEST_RUN_REGISTRY overrides it
# for tests and for anyone deliberately partitioning runs further.
RUN_REGISTRY="${FM_TEST_RUN_REGISTRY:-${TMPDIR:-/tmp}/fm-test-run-registry}"
Comment on lines +121 to +125

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Make the default registry path user-specific.

The comment states the registry is per-user, but that only holds where TMPDIR is per-user. On Linux, TMPDIR is often unset, so the default resolves to the shared /tmp/fm-test-run-registry. Two consequences follow:

  • If another user creates that directory first, mkdir -p succeeds, chmod 0700 fails, and the || true in register_run hides the failure. Records with repository paths become readable by other users.
  • A record written by another user supplies the pid that stop_one_run signals. --stop then sends TERM and KILL to a pid this runner never started.

Add the user id to the default path so runs from different users never share a directory.

🔒 Proposed fix
-RUN_REGISTRY="${FM_TEST_RUN_REGISTRY:-${TMPDIR:-/tmp}/fm-test-run-registry}"
+RUN_REGISTRY="${FM_TEST_RUN_REGISTRY:-${TMPDIR:-/tmp}/fm-test-run-registry-$(id -u)}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Where executing runs register their identity so a concurrent agent can stop
# one exactly instead of pattern-matching a shared command line. Per-user by
# default because TMPDIR is per-user on macOS; FM_TEST_RUN_REGISTRY overrides it
# for tests and for anyone deliberately partitioning runs further.
RUN_REGISTRY="${FM_TEST_RUN_REGISTRY:-${TMPDIR:-/tmp}/fm-test-run-registry}"
# Where executing runs register their identity so a concurrent agent can stop
# one exactly instead of pattern-matching a shared command line. Per-user by
# default because TMPDIR is per-user on macOS; FM_TEST_RUN_REGISTRY overrides it
# for tests and for anyone deliberately partitioning runs further.
RUN_REGISTRY="${FM_TEST_REGISTRY:-${TMPDIR:-/tmp}/fm-test-run-registry-$(id -u)}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/fm-test-run.sh` around lines 121 - 125, Update the RUN_REGISTRY default
in the shell script to include the current user’s identifier in the generated
path, while preserving FM_TEST_RUN_REGISTRY as the explicit override. Ensure the
default registry directory is distinct for different users even when TMPDIR
falls back to /tmp.


# Seconds to wait for a signalled run to write its terminator and exit before
# escalating to SIGKILL on whatever is left.
STOP_GRACE_SECONDS="${FM_TEST_RUN_STOP_GRACE:-10}"

# How many separate-runner shards the portable serial remainder splits into.
# One owner: CI lane names carry this count and are refused when they disagree.
Expand Down Expand Up @@ -128,6 +167,211 @@ now_ms() {
fi
}

# ---------------------------------------------------------------------------
# Run registry: identity-scoped stop, so nobody has to reach for pkill.
#
# Concurrent agents invoke this runner with near-identical command lines
# ("--changed --base origin/main"), so `pkill -f` cannot distinguish one run
# from another and has killed a sibling agent's suite mid-flight. Each
# executing run therefore records its own identity here and --stop acts only on
# those records: by exact run id, or by this repository root.
# ---------------------------------------------------------------------------

run_registry_file() {
printf '%s/%s.run\n' "$RUN_REGISTRY" "$1"
}

# One field out of a registry record. Fields are "key=value", one per line, and
# values may contain "=" so only the first is a separator.
run_record_field() {
local file=$1 key=$2 line
[ -f "$file" ] || return 1
while IFS= read -r line; do
case "$line" in
"$key="*) printf '%s\n' "${line#*=}"; return 0 ;;
esac
done <"$file"
return 1
}

pid_is_alive() {
kill -0 "$1" 2>/dev/null
}

# Direct and transitive children of a pid, deepest last. Used so a stop reaches
# the test script the run is currently executing (and any --jobs workers)
# without ever touching a process the run does not own.
descendant_pids() {
local root=$1 snapshot
snapshot=$(ps -eo pid=,ppid= 2>/dev/null || true)
[ -n "$snapshot" ] || return 0
# One breadth-first pass per level, driven off a single ps snapshot so the
# tree cannot shift underneath a walk that re-reads the process table.
printf '%s\n' "$snapshot" | awk -v root="$root" '
{ child[NR] = $1; parent[NR] = $2; rows = NR }
END {
want[root] = 1
# Bounded by tree depth; each pass adopts children of everything marked
# so far, and stops as soon as a pass marks nothing new.
do {
added = 0
for (i = 1; i <= rows; i++) {
if (want[parent[i]] && !want[child[i]]) {
want[child[i]] = 1
print child[i]
added = 1
}
}
} while (added)
}
'
}

# Drop records whose process is gone. A crashed run must not leave an entry
# that a later --stop could act on, and a recycled pid must not inherit one.
prune_run_registry() {
local file pid
[ -d "$RUN_REGISTRY" ] || return 0
for file in "$RUN_REGISTRY"/*.run; do
[ -f "$file" ] || continue
pid=$(run_record_field "$file" pid || true)
if [ -z "$pid" ] || ! pid_is_alive "$pid"; then
rm -f "$file"
fi
done
}
Comment on lines +232 to +242

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Write registry records atomically.

register_run writes the record in place with a redirect. prune_run_registry can read the same file while that write is in progress. If the pid= line is not yet present, run_record_field returns nothing, the record counts as dead, and rm -f deletes a live run's record. That run then becomes unreachable by --stop, which is the exact failure this feature removes.

The window is small, but concurrent runs are the stated use case: every registering run runs prune_run_registry indirectly whenever another agent calls --list-runs or --stop.

Write to a temporary file in the same directory, then rename it.

🛠️ Proposed fix
   file=$(run_registry_file "$RUN_ID")
+  local tmp_file="$file.tmp.$$"
   {
     printf 'run_id=%s\n' "$RUN_ID"
     printf 'pid=%s\n' "$$"
     printf 'root=%s\n' "$ROOT"
     printf 'fm_home=%s\n' "${FM_HOME:--}"
     printf 'json=%s\n' "${JSON_PATH:--}"
     printf 'selection=%s\n' "$SELECTION_DESC"
     printf 'started=%s\n' "$RUN_STARTED_ISO"
-  } >"$file" || die "could not write run record: $file"
+  } >"$tmp_file" || die "could not write run record: $file"
+  mv -f "$tmp_file" "$file" || die "could not publish run record: $file"
   RUN_REGISTERED_FILE=$file

Also applies to: 249-258

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/fm-test-run.sh` around lines 232 - 242, Update register_run to write the
complete registry record to a temporary file in RUN_REGISTRY, then atomically
rename it to the final .run path only after the write succeeds. Ensure the
temporary file is created in the same directory and cleaned up on failure, while
preserving prune_run_registry’s handling of finalized records.


register_run() {
local file
mkdir -p "$RUN_REGISTRY" || die "could not create run registry: $RUN_REGISTRY"
chmod 0700 "$RUN_REGISTRY" 2>/dev/null || true
file=$(run_registry_file "$RUN_ID")
{
printf 'run_id=%s\n' "$RUN_ID"
printf 'pid=%s\n' "$$"
printf 'root=%s\n' "$ROOT"
printf 'fm_home=%s\n' "${FM_HOME:--}"
printf 'json=%s\n' "${JSON_PATH:--}"
printf 'selection=%s\n' "$SELECTION_DESC"
printf 'started=%s\n' "$RUN_STARTED_ISO"
} >"$file" || die "could not write run record: $file"
RUN_REGISTERED_FILE=$file
}

list_runs() {
local file run_id pid root started selection printed=0
prune_run_registry
for file in "$RUN_REGISTRY"/*.run; do
[ -f "$file" ] || continue
run_id=$(run_record_field "$file" run_id || echo unknown)
pid=$(run_record_field "$file" pid || echo unknown)
root=$(run_record_field "$file" root || echo unknown)
started=$(run_record_field "$file" started || echo unknown)
selection=$(run_record_field "$file" selection || echo unknown)
printf 'FM_TEST_RUN run_id=%s pid=%s started=%s root=%s selection=%s\n' \
"$run_id" "$pid" "$started" "$root" "$selection"
printed=1
done
[ "$printed" -eq 1 ] || log "no live runs registered in $RUN_REGISTRY"
}

# Signal one registered run and, after its grace period, whatever it left
# behind. The run's own handler writes FM_TEST_ABORTED, so its log identifies
# itself as truncated rather than looking like a short clean run.
stop_one_run() {
local file=$1 run_id pid waited child
run_id=$(run_record_field "$file" run_id || echo unknown)
pid=$(run_record_field "$file" pid || true)
if [ -z "$pid" ] || ! pid_is_alive "$pid"; then
rm -f "$file"
log "run $run_id was already gone"
return 0
fi

log "stopping run $run_id (pid $pid)"
# The run's currently-executing test script is signalled alongside the run
# itself. Bash defers a trap until the foreground command returns, so TERMing
# only the run would leave it blocked in the middle of a long test and its
# terminator unwritten until the grace period expired and killed it silently.
for child in $(descendant_pids "$pid"); do
kill -TERM "$child" 2>/dev/null || true
done
kill -TERM "$pid" 2>/dev/null || true

waited=0
while [ "$waited" -lt "$STOP_GRACE_SECONDS" ] && pid_is_alive "$pid"; do
sleep 1
waited=$((waited + 1))
done
Comment on lines +301 to +305

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Validate STOP_GRACE_SECONDS before the wait loop.

FM_TEST_RUN_STOP_GRACE reaches [ "$waited" -lt "$STOP_GRACE_SECONDS" ] unchecked. If a caller exports a non-numeric value, test reports integer expression expected and returns 2. Under set -e the runner then exits after it already sent TERM, so the SIGKILL escalation never runs and the caller gets no FM_TEST_STOPPED line.

Reject a non-numeric value at configuration time.

🛡️ Proposed fix at line 129
 STOP_GRACE_SECONDS="${FM_TEST_RUN_STOP_GRACE:-10}"
+case "$STOP_GRACE_SECONDS" in
+  ''|*[!0-9]*) die "FM_TEST_RUN_STOP_GRACE must be a whole number of seconds: $STOP_GRACE_SECONDS" ;;
+esac
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/fm-test-run.sh` around lines 301 - 305, Validate
FM_TEST_RUN_STOP_GRACE/STOP_GRACE_SECONDS during configuration before the wait
loop, rejecting any non-numeric value with the existing configuration-error
behavior. Ensure the loop around pid_is_alive only receives a validated integer
so invalid input cannot trigger set -e before SIGKILL escalation or suppress the
FM_TEST_STOPPED output.


# Anything still alive is the run's own subtree; the run itself already had
# its chance to exit cleanly. Children are collected before the final kill so
# a test script that ignored TERM cannot outlive its run.
for child in $(descendant_pids "$pid"); do
kill -KILL "$child" 2>/dev/null || true
done
if pid_is_alive "$pid"; then
kill -KILL "$pid" 2>/dev/null || true
log "run $run_id did not exit within ${STOP_GRACE_SECONDS}s; killed"
fi
rm -f "$file"
printf 'FM_TEST_STOPPED run_id=%s pid=%s\n' "$run_id" "$pid"
}

# With a run id, stop exactly that run. Without one, stop only the runs this
# repository root started - never a sibling worktree's run, which is the exact
# collateral damage a broad pkill causes.
stop_runs() {
local want=$1 file root matched=0
prune_run_registry
if [ -n "$want" ]; then
# Run ids are minted by this script as fm-test-run-<ms>-<pid>. Validating
# the shape keeps a caller-supplied id from resolving to a path outside the
# registry, since the id is used to build a file this function rm -f's.
case "$want" in
*/*) die "not a run id: $want (expected fm-test-run-<ms>-<pid>; see --list-runs)" ;;
fm-test-run-[0-9]*-[0-9]*) ;;
*) die "not a run id: $want (expected fm-test-run-<ms>-<pid>; see --list-runs)" ;;
esac
file=$(run_registry_file "$want")
[ -f "$file" ] || die "no live run registered with id: $want (see --list-runs)"
stop_one_run "$file"
return 0
fi
[ -d "$RUN_REGISTRY" ] || die "no live run registered from this root: $ROOT"
for file in "$RUN_REGISTRY"/*.run; do
[ -f "$file" ] || continue
root=$(run_record_field "$file" root || true)
[ "$root" = "$ROOT" ] || continue
stop_one_run "$file"
matched=$((matched + 1))
done
[ "$matched" -gt 0 ] \
|| die "no live run registered from this root: $ROOT (see --list-runs)"
}

# Terminator for an interrupted run. Printed exactly once, to stdout, in place
# of FM_TEST_SUMMARY, so a truncated log is self-identifying.
# shellcheck disable=SC2329 # Invoked indirectly by the signal traps below.
abort_run() {
local signal=$1 status=$2 child
trap - TERM INT HUP
[ "${RUN_ABORTED:-0}" -eq 0 ] || exit "$status"
RUN_ABORTED=1
for child in $(descendant_pids "$$"); do
kill -TERM "$child" 2>/dev/null || true
done
printf 'FM_TEST_ABORTED %s run_id=%s signal=%s completed=%s selected=%s\n' \
"$(now_iso)" "${RUN_ID:-unknown}" "$signal" "${TOTAL:-0}" "${SELECTED_TOTAL:-0}"
exit "$status"
}

# shellcheck disable=SC2329 # Invoked indirectly by the EXIT trap below.
cleanup_run() {
[ -z "${RUN_REGISTERED_FILE:-}" ] || rm -f "$RUN_REGISTERED_FILE"
[ -z "${RUN_TMP:-}" ] || rm -rf "$RUN_TMP"
}

# Primary family for one tests/*.test.sh basename. Unmapped scripts are
# unclassified so new tests are still runnable and visible in summaries.
family_for_basename() {
Expand Down Expand Up @@ -1270,6 +1514,26 @@ while [ "$#" -gt 0 ]; do
CHECK_COVERAGE=1
shift
;;
--list-runs)
LIST_RUNS=1
shift
;;
--stop)
STOP_REQUESTED=1
shift
# An optional bare run id; anything starting with "-" is a later option.
if [ "$#" -gt 0 ]; then
case "$1" in
-*) ;;
*) STOP_RUN_ID=$1; shift ;;
esac
fi
;;
--stop=*)
STOP_REQUESTED=1
STOP_RUN_ID=${1#--stop=}
shift
;;
Comment on lines +1532 to +1536

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject an empty --stop= value.

--stop= sets STOP_RUN_ID to the empty string. stop_runs then takes the no-id branch and stops every run registered from this root. The caller used the = form to name one run, so the fallback stops runs the caller did not name.

🛠️ Proposed fix
     --stop=*)
       STOP_REQUESTED=1
       STOP_RUN_ID=${1#--stop=}
+      [ -n "$STOP_RUN_ID" ] \
+        || die "--stop= needs a run id (use bare --stop for this root; see --list-runs)"
       shift
       ;;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
--stop=*)
STOP_REQUESTED=1
STOP_RUN_ID=${1#--stop=}
shift
;;
--stop=*)
STOP_REQUESTED=1
STOP_RUN_ID=${1#--stop=}
[ -n "$STOP_RUN_ID" ] \
|| die "--stop= needs a run id (use bare --stop for this root; see --list-runs)"
shift
;;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bin/fm-test-run.sh` around lines 1532 - 1536, Validate the extracted
STOP_RUN_ID in the --stop=* argument branch before setting STOP_REQUESTED or
continuing. Reject an empty value with the script’s existing invalid-argument
behavior, and only invoke the single-run stop path when a non-empty run ID was
supplied; preserve the no-ID behavior for the separate --stop form.

--aggregate-json)
[ "$#" -gt 1 ] || die "--aggregate-json requires an output path"
AGGREGATE_OUT=$2
Expand Down Expand Up @@ -1334,6 +1598,16 @@ if [ "$LIST_LANES" -eq 1 ]; then
exit 0
fi

if [ "$LIST_RUNS" -eq 1 ]; then
list_runs
exit 0
fi

if [ "$STOP_REQUESTED" -eq 1 ]; then
stop_runs "$STOP_RUN_ID"
exit 0
fi

if [ "$CHECK_COVERAGE" -eq 1 ]; then
run_coverage_guard
exit $?
Expand Down Expand Up @@ -1443,16 +1717,26 @@ RUN_TMP=$(mktemp -d "${TMPDIR:-/tmp}/fm-test-run.XXXXXX")
RECORDS="$RUN_TMP/records.tsv"
FAMILIES_TSV="$RUN_TMP/families.tsv"
: >"$RECORDS"
trap 'rm -rf "$RUN_TMP"' EXIT

RUN_STARTED_ISO=$(now_iso)
RUN_STARTED_MS=$(now_ms)
RUN_ID="fm-test-run-${RUN_STARTED_MS}-$$"
RUN_REGISTERED_FILE=
RUN_ABORTED=0
TOTAL=0
SELECTED_TOTAL=${#SCRIPTS[@]}
FAILED=0
SKIPPED_GATE=0
AGG_RC=0

# Registered before the first script so a stop issued at any point during the
# run finds this run's identity, and torn down on every exit path.
trap 'cleanup_run' EXIT
trap 'abort_run TERM 143' TERM
trap 'abort_run INT 130' INT
trap 'abort_run HUP 129' HUP
register_run

# Family accumulators as TSV lines updated in-memory via temp files.
# family -> count, duration_ms, failed
family_bump() {
Expand Down
2 changes: 1 addition & 1 deletion docs/scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ The shared no-mistakes gate refusal for fleet lifecycle entrypoints is summarize
| `fm-install-herdr.sh` | Install CI's exact-version Herdr pin with official asset URL, SHA-256, and protocol checks |
| `fm-install-treehouse.sh`| Install CI's exact-version Treehouse pin for real-Herdr E2E that needs spawn worktrees |
| `fm-herdr-ci-cleanup.sh` | Snapshot and tear down only job-owned `fm-lab-*` sessions in the Herdr CI lane |
| `fm-test-run.sh` | Behavior-test runner: selection, portable lanes, proven-isolated `--jobs`, coverage guard, timing/JSON |
| `fm-test-run.sh` | Behavior-test runner: selection, portable lanes, proven-isolated `--jobs`, coverage guard, timing/JSON, identity-scoped `--list-runs`/`--stop` |
| `fm-test-isolation-proof.sh` | Concurrent isolation proof and proven-isolated candidate set owner |
| `fm-ensure-agents-md.sh` | Ensure a project's real `AGENTS.md`, its `CLAUDE.md` symlink, and the canonical self-governance section |
| `fm-guard.sh` | Warn on primary-checkout tangles, pending queued wakes, and unhealthy supervision |
Expand Down
Loading
Loading