From 6ba36f0455657ee389f8b7e73fb4bec99136136f Mon Sep 17 00:00:00 2001 From: LucaLin <78164141+LucaLin233@users.noreply.github.com> Date: Tue, 8 Sep 2026 15:42:37 +0000 Subject: [PATCH 1/3] fix(push): avoid substitution parsing during active job polling --- tools/push.sh | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tools/push.sh b/tools/push.sh index 86090a1..ad31cd4 100755 --- a/tools/push.sh +++ b/tools/push.sh @@ -941,14 +941,11 @@ process_identity_matches() { } job_is_active() { - local expected="$1" pid active_jobs - # Bash 5.2 can report a trap parser EOF when HUP interrupts process substitution. - # Snapshot the inherited job table without process substitution or word splitting. - active_jobs=$(jobs -pr) || return 1 - while IFS= read -r pid; do - [[ "$pid" == "$expected" ]] && return 0 - done <<< "$active_jobs" - return 1 + local expected="$1" + [[ "$expected" =~ ^[1-9][0-9]*$ ]] || return 1 + # Both process and command substitution reproduced HUP parser EOF on Bash 5.2. + # Drain the entire jobs stream: grep -q could close early and cause SIGPIPE. + jobs -pr | grep -Fx -- "$expected" > /dev/null } worker_registration_begin_critical() { From 2d4fb46b4d208f2222d213f224994f12f633d0d2 Mon Sep 17 00:00:00 2001 From: LucaLin <78164141+LucaLin233@users.noreply.github.com> Date: Tue, 8 Sep 2026 15:42:56 +0000 Subject: [PATCH 2/3] test(push): gate pipeline polling and retain failed snapshot reproducer --- tests/test-hup-parser.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test-hup-parser.sh b/tests/test-hup-parser.sh index 26b8f43..00434a7 100644 --- a/tests/test-hup-parser.sh +++ b/tests/test-hup-parser.sh @@ -19,6 +19,7 @@ end=$((SECONDS + 2)) case "$mode" in plain) while (( SECONDS < end )); do :; done ;; command) while (( SECONDS < end )); do value=$(printf x); [[ $value == x ]]; done ;; + pipeline) while (( SECONDS < end )); do jobs -pr | grep -Fx -- 1 > /dev/null || :; done ;; snapshot) while (( SECONDS < end )); do active_jobs=$(jobs -pr); while IFS= read -r value; do :; done <<< "$active_jobs"; done ;; process) while (( SECONDS < end )); do while IFS= read -r value; do :; done < <(jobs -pr); done ;; *) exit 90 ;; @@ -49,10 +50,11 @@ printf "DIAG: mode=%s round=%s delay=%s exit=%s\n" "$mode" "$round" "$delay" "$s CONTROL # 3 modes x 6 cases, at most 5 seconds per case (including forced teardown). # Do not retry failures. Delay varies delivery, not a claim of exact parser timing. -# Legacy process mode already reproduced EOF in run 34226553908. +# Process mode failed in 34226553908; snapshot failed in 34245125939. +# Keep both failed implementations as explicit diagnostic controls. # Keep it available explicitly; the default gate validates the replacement. -modes="plain command snapshot" -if [[ ${HUP_PARSER_INCLUDE_LEGACY:-false} == true ]]; then modes="$modes process"; fi +modes="plain command pipeline" +if [[ ${HUP_PARSER_INCLUDE_LEGACY:-false} == true ]]; then modes="$modes process snapshot"; fi for mode in $modes; do round=0 for delay in 0 0.001 0.005 0.01 0.02 0.05; do From a9da81193995e54094ac1691f40df6aeb02b90c2 Mon Sep 17 00:00:00 2001 From: LucaLin <78164141+LucaLin233@users.noreply.github.com> Date: Tue, 8 Sep 2026 15:51:58 +0000 Subject: [PATCH 3/3] test(push): reject unexpected pipeline probe errors --- tests/test-hup-parser.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/test-hup-parser.sh b/tests/test-hup-parser.sh index 00434a7..61fb052 100644 --- a/tests/test-hup-parser.sh +++ b/tests/test-hup-parser.sh @@ -19,7 +19,14 @@ end=$((SECONDS + 2)) case "$mode" in plain) while (( SECONDS < end )); do :; done ;; command) while (( SECONDS < end )); do value=$(printf x); [[ $value == x ]]; done ;; - pipeline) while (( SECONDS < end )); do jobs -pr | grep -Fx -- 1 > /dev/null || :; done ;; + pipeline) + while (( SECONDS < end )); do + probe_status=0 + jobs -pr | grep -Fx -- 1 > /dev/null || probe_status=$? + # No fixture job has PID 1: only grep no-match is expected. + [[ $probe_status == 1 ]] || exit 93 + done + ;; snapshot) while (( SECONDS < end )); do active_jobs=$(jobs -pr); while IFS= read -r value; do :; done <<< "$active_jobs"; done ;; process) while (( SECONDS < end )); do while IFS= read -r value; do :; done < <(jobs -pr); done ;; *) exit 90 ;;