fix(orders): a pending order's age comes from the filename, not the mtime

`coord-order-done --return` rewrites the order file's mtime, and both age
surfaces read mtime, so putting an order back reset the very reading that
says how long it has waited. An order returned three times could never look
old - on the one surface that exists precisely so a repo nobody opens still
shows something.

Found by reading the board right after this repo returned an order of its
own, not by looking for it: a file whose name says 2026-09-02 rendered
`ORDRE 1:0d` and `pending, 0d old` minutes later. Verified live after the
fix: the same order now reads 1d.

Two questions, two sources, and only one of them moved. A PENDING order's
age is "how long has this sat with no owner" = now - delivery time, which
only the filename carries and nothing rewrites. A CLAIMED order's age is
"how long has it been in flight", which is the claim's own mtime and was
already right. So oldest_pending_age() sits BESIDE oldest_order_age(), and
pending_age_of() beside age_of() - switching FLY to the filename would
answer the delivery question in the column that asks the flight question.
An unparseable filename yields "?" for the whole reading, never a
fabricated 0, because an unmeasured order could be the oldest one.

TDD, red first: orders-selftest section 11 (110 -> 116) and board-selftest
section 30 (360 -> 368), each asserting its own ground truth before
anything depends on it, with controls that a freshly delivered order still
reads 0d and that FLY did not move. Mutation-verified in both files:
restoring the mtime read turns exactly the defect checks red and leaves
every control green.

Section 28's fixtures were rewritten as part of this rather than
incidentally: they encoded their ages in `touch -t` while their filenames
held fixed 2026-01/2026-08 dates, which a filename-based reading makes both
wrong and time-dependent. They now compute their stems from `date -v` and
the section asserts two ground truths, the filename for ORDRE and the mtime
for FLY.

Order 20260903T185736Z-1290610855 (.claude). Version 0.32.1 across all
seven files; no catalog change in this session.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-03 22:17:26 +02:00
commit 5316688844
13 changed files with 332 additions and 24 deletions

View file

@ -1920,9 +1920,14 @@ for i in 1 2 3; do
printf -- '---\nfrom: x\nto: ord-both\nsubject: m%s\n---\nbody\n' "$i" \
> "$CLAUDE_COORD_DIR/ord-both/inbox/2026010${i}T000000Z-${i}-from-x.md"
done
# The PENDING filenames carry TODAY's stamp: since ORDRE 20260903T185736Z the
# ORDRE age is read from the name, so a fixed 2026-01 name would render its real
# delivery age here and this row asserts 2:0d. Claimed fixtures keep their fixed
# names - FLY still reads the mtime.
ORD_TODAY="$(date -u +%Y%m%dT%H%M%SZ)"
for i in 1 2; do
printf -- '---\nfrom: d\nto: ord-both\norder-id: o%s\nsubject: order %s\n---\nbody\n' "$i" "$i" \
> "$CLAUDE_COORD_DIR/ord-both/orders/2026010${i}T000000Z-${i}-from-d.md"
> "$CLAUDE_COORD_DIR/ord-both/orders/${ORD_TODAY}-${i}-from-d.md"
done
# A CLAIMED order is deliberately NOT counted: the column answers "what can a
# session pick up here", and one already in flight cannot be. Counting it would
@ -2192,8 +2197,9 @@ mkfly fly-inflight planned; mkorder fly-inflight claimed 20260101T000000Z-1-fro
mkfly fly-empty planned
# Both states at once, so the two counts are provably read from different dirs.
mkfly fly-mixed planned
mkorder fly-mixed pending 20260102T000000Z-2-from-d
mkorder fly-mixed pending 20260103T000000Z-3-from-d
FLY_TODAY="$(date -u +%Y%m%dT%H%M%SZ)"
mkorder fly-mixed pending "${FLY_TODAY}-2-from-d"
mkorder fly-mixed pending "${FLY_TODAY}-3-from-d"
mkorder fly-mixed claimed 20260104T000000Z-4-from-d
FLY_OUT="$("$BOARD" --roots "$FLY_ROOT" 2>/dev/null)"
@ -2221,7 +2227,7 @@ check "the legend denies that FLY proves a session is alive" $?
# deferred repos were NOT free (2 held a pending order, 1 owed a reply, 1 had
# an uncommitted tree). All four conditions are required.
mkfly fly-free done
mkfly fly-busy-order done; mkorder fly-busy-order pending 20260105T000000Z-5-from-d
mkfly fly-busy-order done; mkorder fly-busy-order pending "${FLY_TODAY}-5-from-d"
mkfly fly-busy-fly done; mkorder fly-busy-fly claimed 20260106T000000Z-6-from-d
mkfly fly-busy-mail done
mkdir -p "$CLAUDE_COORD_DIR/fly-busy-mail/inbox"
@ -2576,9 +2582,17 @@ check "exit3: a nonzero that is not 3 is caught too, and names its own status" $
# problem, and the newest reading is precisely what would hide it. This is not
# a new mechanism in the file - ALDER (STATE.md mtime) and SISTE (last commit)
# already read a clock the same way.
#
# Since ORDRE 20260903T185736Z the PENDING age is read from the FILENAME, so
# these fixtures carry their intended age in the NAME rather than only in a
# `touch -t`. The stems are computed once - the timestamp embeds HHMMSS, so
# recomputing one a second later names a different file. FLY still reads the
# mtime, which is why the claimed fixture keeps its touch.
AGROOT="$(mktemp -d)"
AGCOORD="$(mktemp -d)"
AG_OLD="$(date -v-10d +%Y%m%d%H%M)"
AG_OLD_TS="$(date -u -v-10d +%Y%m%dT%H%M%SZ)"
AG_NEW_TS="$(date -u +%Y%m%dT%H%M%SZ)"
mk_ag_repo() {
mkrepo "$AGROOT/$1"
@ -2599,15 +2613,15 @@ mk_ag_order() { # $1=repo $2=subdir ("orders" or "orders/claimed") $3=file $4=t
# ag-old: one fresh order AND one ten days old. The whole point of the section.
mk_ag_repo ag-old
mk_ag_order ag-old orders 20260829T000000Z-fresh -
mk_ag_order ag-old orders 20260818T000000Z-stale "$AG_OLD"
mk_ag_order ag-old orders "${AG_NEW_TS}-fresh" -
mk_ag_order ag-old orders "${AG_OLD_TS}-stale" "$AG_OLD"
# ag-fresh: KNOWN-POSITIVE CONTROL. Two orders, both fresh. If the assertion
# below could not tell these two repos apart it would pass on anything - this
# is the tree "where the age is wrong" that proves the check can fail.
mk_ag_repo ag-fresh
mk_ag_order ag-fresh orders 20260829T000001Z-a -
mk_ag_order ag-fresh orders 20260829T000002Z-b -
mk_ag_order ag-fresh orders "${AG_NEW_TS}-a" -
mk_ag_order ag-fresh orders "${AG_NEW_TS}-b" -
# ag-none: no orders at all. "0 days old" and "no orders" are two different
# facts and must not render the same - the same reason FLY exists next to ORDRE.
@ -2617,7 +2631,7 @@ mk_ag_repo ag-none
# that most needs this: nothing un-claims an order when the session dies, so a
# claim with no age is the 117-hour claim with its only counter-evidence removed.
mk_ag_repo ag-fly
mk_ag_order ag-fly orders/claimed 20260818T000001Z-inflight "$AG_OLD"
mk_ag_order ag-fly orders/claimed "${AG_OLD_TS}-inflight" "$AG_OLD"
AGOUT="$(CLAUDE_COORD_DIR="$AGCOORD" "$BOARD" --roots "$AGROOT" 2>/dev/null)"
ag_row() { printf '%s' "$AGOUT" | grep "^$1 "; }
@ -2625,9 +2639,15 @@ ag_row() { printf '%s' "$AGOUT" | grep "^$1 "; }
# Ground truth for the fixture itself: the stale file really is ~10 days old.
# Asserted before anything depends on it, so a broken `touch -t` fails here
# rather than silently turning the checks below into a test of nothing.
ag_gt="$(( ( $(date +%s) - $(stat -f %m "$AGCOORD/ag-old/orders/20260818T000000Z-stale.md") ) / 86400 ))"
# Two ground truths, because the two columns now read two different sources.
# ORDRE depends on the FILENAME, FLY on the mtime, and a fixture check that
# guarded only one of them would leave the other assertion resting on nothing.
ag_gt_name="$(( ( $(date -u +%s) - $(date -u -j -f %Y%m%d%H%M%S "$(printf '%s' "$AG_OLD_TS" | tr -dc '0-9')" +%s) ) / 86400 ))"
[ "$ag_gt_name" -eq 10 ]
check "orderage: ground truth - the stale fixture's FILENAME says 10 days" $?
ag_gt="$(( ( $(date +%s) - $(stat -f %m "$AGCOORD/ag-fly/orders/claimed/${AG_OLD_TS}-inflight.md") ) / 86400 ))"
[ "$ag_gt" -eq 10 ]
check "orderage: ground truth - the fixture's stale order really is 10 days old" $?
check "orderage: ground truth - the in-flight fixture's MTIME really is 10 days old" $?
ag_cells() { ag_row "$1" | cut -c89- ; }
[ "$(ag_cells ag-old | awk '{print $1}')" = "2:10d" ]
@ -2940,6 +2960,90 @@ vsum_after="$(find "$VROOT" -type f | sort | wc -l)"
check "voyage: board wrote nothing to the scanned tree (read-only preserved)" $?
/bin/rm -rf "$VROOT" "$VCOORD" 2>/dev/null
# --- 30. ORDRE's pending age comes from the FILENAME, never the mtime -------
# ORDRE 20260903T185736Z-1290610855 (.claude, 2026-09-03). Found by reading the
# board right after this repo returned an order of its own: `--return` rewrites
# the order file's mtime, and ORDRE read mtime, so a 1-day-old order rendered
# `1:0d`. An order returned three times could never look old on the one surface
# that exists so a repo nobody opens still shows something.
#
# PM decision - two questions, two sources. A PENDING order's age is "how long
# has this sat with no owner" = now - DELIVERY time, which only the filename
# carries and nothing rewrites. A CLAIMED order's age is "how long has it been
# in flight", which is the claim's own mtime and is already right.
PAROOT="$(mktemp -d)"
PACOORD="$(mktemp -d)"
pa_ts() { date -u -v-"$1"d +%Y%m%dT%H%M%SZ; }
mk_pa_repo() {
mkrepo "$PAROOT/$1"
{
echo "# STATE - $1"
echo ""
printf '## %s NESTE %s START HER\n' "$HAND" "$EMDASH"
echo "<!-- board: status=in-progress; blocked-on=-; next-cost=Sonnet 5/high -->"
echo "Et steg."
} > "$PAROOT/$1/STATE.md"
}
mk_pa_order() { # $1=repo $2=subdir $3=full filename stem (carries the timestamp)
mkdir -p "$PACOORD/$1/$2"
printf -- '---\nfrom: x\nto: %s\n---\nDo a thing.\n' "$1" > "$PACOORD/$1/$2/$3.md"
}
# The stems are computed ONCE and reused: pa_ts embeds HHMMSS, so recomputing
# it a second later names a different file than the one that was created.
pa_ret_stem="$(pa_ts 3)-1111111111-from-x"
pa_fresh_stem="$(pa_ts 0)-2222222222-from-x"
pa_fly_stem="$(pa_ts 9)-3333333333-from-x"
# pa-returned: filename says 3 days ago, mtime is NOW - exactly what a return
# leaves behind. This is the defect, reproduced in a fixture.
mk_pa_repo pa-returned
mk_pa_order pa-returned orders "$pa_ret_stem"
# pa-fresh: KNOWN-POSITIVE CONTROL. Delivered today, so it must still read 0d -
# without this, an assertion of "3d" would pass against a function that always
# says 3.
mk_pa_repo pa-fresh
mk_pa_order pa-fresh orders "$pa_fresh_stem"
# pa-fly: an OLD filename claimed just now. FLY must stay on the mtime and read
# 0d, or the fix has quietly changed the other question's answer too.
mk_pa_repo pa-fly
mk_pa_order pa-fly orders/claimed "$pa_fly_stem"
PAOUT="$(CLAUDE_COORD_DIR="$PACOORD" "$BOARD" --roots "$PAROOT" 2>/dev/null)"
pa_cells() { printf '%s' "$PAOUT" | grep "^$1 " | cut -c89- ; }
# Ground truth for the fixture first: the mtime really is fresh, so a green
# 30b cannot come from the file secretly being 3 days old on disk.
pa_gt="$(( ( $(date +%s) - $(stat -f %m "$PACOORD/pa-returned/orders/$pa_ret_stem.md") ) / 86400 ))"
[ "$pa_gt" -eq 0 ]
check "pendingage: ground truth - the returned fixture's mtime is TODAY" $?
[ "$(pa_cells pa-returned | awk '{print $1}')" = "1:3d" ]
check "pendingage: ORDRE reads the DELIVERY age from the filename, not the mtime" $?
[ "$(pa_cells pa-returned | awk '{print $1}')" = "1:0d" ]; [ $? -ne 0 ]
check "pendingage: a rewritten mtime can no longer reset a pending order's age" $?
[ "$(pa_cells pa-fresh | awk '{print $1}')" = "1:0d" ]
check "pendingage: control - an order delivered today still reads 0d" $?
[ "$(pa_cells pa-fly | awk '{print $2}')" = "1:0d" ]
check "pendingage: FLY still reads the claim's mtime - the other question is unchanged" $?
[ "$(pa_cells pa-fly | awk '{print $2}')" = "1:9d" ]; [ $? -ne 0 ]
check "pendingage: FLY did NOT switch to the filename with ORDRE" $?
# A name the grammar does not produce has no readable delivery time. "?" is the
# whole reading, never a skipped file: an unmeasured order could be the oldest,
# which is the same rule the mtime path already carried.
mk_pa_repo pa-bad
mk_pa_order pa-bad orders "not-a-timestamp"
PAOUT2="$(CLAUDE_COORD_DIR="$PACOORD" "$BOARD" --roots "$PAROOT" 2>/dev/null)"
[ "$(printf '%s' "$PAOUT2" | grep "^pa-bad " | cut -c89- | awk '{print $1}')" = "1:?" ]
check "pendingage: an unparseable filename reads ?, never a fabricated 0" $?
/bin/rm -rf "$PAROOT" "$PACOORD" 2>/dev/null
echo ""
echo "board-selftest: $PASS passed, $FAIL failed"
[ "$FAIL" -eq 0 ] || exit 1