From d5452a4902e4371a270e44e25d46a8019df426f1 Mon Sep 17 00:00:00 2001 From: Jean Brito Date: Sat, 10 Oct 2026 05:38:43 -0300 Subject: [PATCH 1/2] fix: read the lock age with GNU stat first so Linux appends do not die The stale-lock sweep in ledger-append.sh ran `stat -f %m || stat -c %Y`. On Linux, `stat -f` is filesystem status: it exits 0 and prints text, so the age arithmetic failed under `set -u` and the writer exited before it appended. Under contention, entries were lost (17 of 20 in an Ubuntu container), and a stale lock blocked every append. Run `stat -c %Y` first. BSD stat rejects `-c`, so macOS falls through to `stat -f %m`. Ignore any value that is not a number. verify.sh gains a check with a lock dir dated 2020. It fails on Linux with the old script and passes with this one. --- scripts/ledger-append.sh | 7 +++++-- verify.sh | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/scripts/ledger-append.sh b/scripts/ledger-append.sh index 68d272d..9015d23 100755 --- a/scripts/ledger-append.sh +++ b/scripts/ledger-append.sh @@ -83,8 +83,11 @@ timeout_hit=0 while :; do # Sweep a stale lock (crashed/killed holder) before every attempt. if [ -d "$LOCK_DIR" ]; then - lock_mtime=$(stat -f %m "$LOCK_DIR" 2>/dev/null || stat -c %Y "$LOCK_DIR" 2>/dev/null || echo "") - if [ -n "$lock_mtime" ]; then + # GNU stat first: on Linux, `stat -f` means filesystem status and exits 0 + # with text output, which broke the arithmetic below under `set -u`. BSD + # stat rejects `-c`, so macOS falls through to `-f %m`. + lock_mtime=$(stat -c %Y "$LOCK_DIR" 2>/dev/null || stat -f %m "$LOCK_DIR" 2>/dev/null || echo "") + if [[ "$lock_mtime" =~ ^[0-9]+$ ]]; then lock_age=$(( $(date +%s) - lock_mtime )) if [ "$lock_age" -gt 60 ]; then rmdir "$LOCK_DIR" 2>/dev/null || rm -rf "$LOCK_DIR" 2>/dev/null diff --git a/verify.sh b/verify.sh index 9b25595..5ed6061 100755 --- a/verify.sh +++ b/verify.sh @@ -406,6 +406,22 @@ else check "ledger-append.sh concurrency: lock dir removed after run" "$PASS" fi +# A lock dir left by a crashed writer (2020 mtime) must be swept at once on +# both GNU and BSD stat. On Linux, `stat -f` is filesystem status and once +# broke the age arithmetic, so the writer died and the entry was lost. +TMPDIR_STALE=$(mktemp -d) +mkdir -p "$TMPDIR_STALE/.localdev/workflow/.done.md.lock" +touch -t 202001010000 "$TMPDIR_STALE/.localdev/workflow/.done.md.lock" +(cd "$TMPDIR_STALE" && printf '## stale-entry\n' | bash "$SCRIPT_DIR/scripts/ledger-append.sh" done 2>/dev/null) +if grep -q '^## stale-entry$' "$TMPDIR_STALE/.localdev/workflow/done.md" 2>/dev/null \ + && ! grep -q 'lock-timeout' "$TMPDIR_STALE/.localdev/workflow/done.md" \ + && [ ! -d "$TMPDIR_STALE/.localdev/workflow/.done.md.lock" ]; then + check "ledger-append.sh: stale lock swept at once, entry appended without timeout" "$PASS" +else + check "ledger-append.sh: stale lock swept at once, entry appended without timeout" "$FAIL" +fi +rm -rf "$TMPDIR_STALE" + (cd "$TMPDIR_LA" && echo hi | bash "$SCRIPT_DIR/scripts/ledger-append.sh" bogus >/dev/null 2>/tmp/ledger_err_$$.txt) LA_BOGUS_EXIT=$? if [ "$LA_BOGUS_EXIT" -ne 0 ] && [ -s "/tmp/ledger_err_$$.txt" ]; then From ca4b52b856dad97d90f49da8e2ad52861af48fd9 Mon Sep 17 00:00:00 2001 From: Jean Brito Date: Sat, 10 Oct 2026 05:39:22 -0300 Subject: [PATCH 2/2] fix: quote the done argument for shellcheck --- verify.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/verify.sh b/verify.sh index 5ed6061..8c22117 100755 --- a/verify.sh +++ b/verify.sh @@ -412,7 +412,7 @@ fi TMPDIR_STALE=$(mktemp -d) mkdir -p "$TMPDIR_STALE/.localdev/workflow/.done.md.lock" touch -t 202001010000 "$TMPDIR_STALE/.localdev/workflow/.done.md.lock" -(cd "$TMPDIR_STALE" && printf '## stale-entry\n' | bash "$SCRIPT_DIR/scripts/ledger-append.sh" done 2>/dev/null) +(cd "$TMPDIR_STALE" && printf '## stale-entry\n' | bash "$SCRIPT_DIR/scripts/ledger-append.sh" "done" 2>/dev/null) if grep -q '^## stale-entry$' "$TMPDIR_STALE/.localdev/workflow/done.md" 2>/dev/null \ && ! grep -q 'lock-timeout' "$TMPDIR_STALE/.localdev/workflow/done.md" \ && [ ! -d "$TMPDIR_STALE/.localdev/workflow/.done.md.lock" ]; then