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
8 changes: 8 additions & 0 deletions docs/dev_guide_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2595,6 +2595,14 @@ two newer consecutive decisive green runs before it posts an evidence comment
and closes an incident as completed. Active, pending, malformed, or
concurrent-change cases remain open.

The Actions run evidence window is paginated. The reconciler reads full
workflow-run pages and stops only after two decisive completed green/red runs
are visible, so a cancellation-saturated newest page cannot hide the decisive
history. The default page budget is ten; `--max-run-pages N` changes it, and
the legacy `--run-limit N` option is retained as an alias for that page budget.
If the budget is exhausted before two decisive runs are found, the helper
fails closed instead of classifying an incomplete window.

The helper is report-only unless `--apply` is supplied, so an offline or local
inspection can use:

Expand Down
79 changes: 53 additions & 26 deletions scripts/dev/ci_uv_sync_diag.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,51 @@ set -uo pipefail
label="${1:-uv-sync-diag}"

# Bounded tree sizing (issue #8249): `du` walks scale with cache/venv size and
# shared-host I/O contention (measured 28s for a 60GB cache against the 30s
# test budget, so loaded hosts exceed it). Each probe below is capped so this
# advisory diagnostic stays fast; on timeout it reports
# shared-host I/O contention. With GNU timeout(1), each tree-size probe below
# is capped so this advisory diagnostic stays fast; on timeout it reports
# `unavailable-timed-out` instead of hanging the caller. Override the cap with
# ROBOT_SF_DIAG_DU_TIMEOUT_SECONDS (default 10). Hosts without GNU timeout(1)
# (e.g. macOS) keep the previous unbounded behavior.
# (e.g. macOS) keep the previous direct-`du` fallback behavior.
diag_du_timeout="${ROBOT_SF_DIAG_DU_TIMEOUT_SECONDS:-10}"
if ! [[ "$diag_du_timeout" =~ ^[0-9]+$ ]]; then
if ! [[ "$diag_du_timeout" =~ ^[1-9][0-9]*$ ]]; then
diag_du_timeout=10
fi
# GNU timeout(1) is absent on some hosts (e.g. stock macOS bash 3.2 runners);
# without it keep the previous unbounded behavior. The function form (rather
# than an arg array) stays safe under `set -u` on old bash versions.
du_timeout_secs=""
if command -v timeout >/dev/null 2>&1; then
du_timeout_secs="$diag_du_timeout"
# without it keep the previous direct-`du` behavior. Detect GNU explicitly so
# a non-GNU command with the same name does not receive incompatible options.
# The function form (rather than an arg array) stays safe under `set -u` on old
# bash versions.
du_timeout_bin=""
if command -v timeout >/dev/null 2>&1 &&
timeout --version 2>/dev/null | grep -q "GNU coreutils"; then
du_timeout_bin="$(command -v timeout)"
fi
du_timeout_kill_after_secs=2
bounded_du() {
if [[ -n "${du_timeout_secs:-}" ]]; then
timeout "$du_timeout_secs" "$@"
if [[ -n "${du_timeout_bin:-}" ]]; then
"$du_timeout_bin" --kill-after="${du_timeout_kill_after_secs}s" "$diag_du_timeout" "$@"
else
"$@"
fi
}

du_timed_out() {
local rc="$1"
[[ -n "${du_timeout_bin:-}" && ( "$rc" -eq 124 || "$rc" -eq 137 ) ]]
}

report_du_failure() {
local prefix="$1"
local rc="$2"
if du_timed_out "$rc"; then
echo " ${prefix}_sizing_status=timed-out"
echo " ${prefix}_sizing_timeout_seconds=${diag_du_timeout}"
else
echo " ${prefix}_sizing_status=error"
fi
echo " ${prefix}_sizing_exit_code=${rc}"
}

echo "::group::${label}"

echo "uv_sync_diag runner_info"
Expand All @@ -52,11 +72,6 @@ echo "uv_sync_diag uv_info"
if command -v uv >/dev/null 2>&1; then
echo " uv_version=$(uv --version 2>/dev/null || echo unknown)"
echo " uv_cache_dir=$(uv cache dir 2>/dev/null || echo unknown)"
# Best-effort cache size report; older uv versions may not have 'uv cache size'.
uv_cache_size="$(uv cache size 2>/dev/null || true)"
if [[ -n "$uv_cache_size" ]]; then
echo " uv_cache_size=${uv_cache_size}"
fi
else
echo " uv_version=not_installed"
fi
Expand Down Expand Up @@ -100,15 +115,14 @@ if [[ -d "$cache_dir" ]]; then
# tree up to a dozen times and risking preflight timeouts on large caches.
# The captured output is then parsed in a single awk pass (pure in-memory,
# no further disk I/O), preserving the curated key names and ordering.
# The walk itself is capped by bounded_du (issue #8249); exit 124 means the
# probe timed out under contention, which is reported, not retried.
# The walk itself is capped by bounded_du (issue #8249). It is the sole
# cache-size traversal; `uv cache size` is intentionally not called because
# that full-cache operation cannot be deadline controlled here.
cache_du=""
cache_du_rc=0
cache_du="$(bounded_du du -h -d 1 "$cache_dir" 2>/dev/null)" || cache_du_rc=$?
if [[ "$cache_du_rc" -eq 124 ]]; then
echo " cache_total_size=unavailable-timed-out"
echo " cache_sizing_note=du exceeded ${diag_du_timeout}s under host contention"
else
if [[ "$cache_du_rc" -eq 0 ]]; then
echo " cache_sizing_status=ok"
printf '%s\n' "$cache_du" | awk -F'\t' -v dir="$cache_dir" '
{ size[$2] = $1 }
END {
Expand All @@ -120,6 +134,13 @@ if [[ -d "$cache_dir" ]]; then
}
}
'
else
report_du_failure "cache" "$cache_du_rc"
if du_timed_out "$cache_du_rc"; then
echo " cache_total_size=unavailable-timed-out"
else
echo " cache_total_size=unavailable-error"
fi
fi
else
echo " cache_dir=${cache_dir} (does not exist)"
Expand All @@ -129,10 +150,16 @@ echo "uv_sync_diag venv_info"
if [[ -d .venv ]]; then
venv_du_rc=0
venv_du="$(bounded_du du -sh .venv 2>/dev/null)" || venv_du_rc=$?
if [[ "$venv_du_rc" -eq 124 ]]; then
echo " venv_size=unavailable-timed-out"
else
if [[ "$venv_du_rc" -eq 0 ]]; then
echo " venv_sizing_status=ok"
printf '%s\n' "$venv_du" | awk '{print " venv_size="$1}' || true
else
report_du_failure "venv" "$venv_du_rc"
if du_timed_out "$venv_du_rc"; then
echo " venv_size=unavailable-timed-out"
else
echo " venv_size=unavailable-error"
fi
fi
if [[ -x .venv/bin/python ]]; then
echo " python_version=$(.venv/bin/python --version 2>&1 || true)"
Expand Down
Loading
Loading