test(board): pin the "field inserted before neste" class; 16 of 16 mutants die
An independent review ran 16 mutants of the PLAN column against the 461 board checks and 5 survived: - --row taking neste from a stale index (neste=5d|...) - --inbox-plan taking neste from a stale index (neste=5d) - the no-STATE.md record one field short (plan=(ingen STATE.md)) - Nd measured behind NOW instead of behind the last commit - the '?' branch (a plan with no commit) rendered as '-' Section 34 part 8 adds a fixture for each: a NESTE with a '|' inside, pinned exactly in --row and --inbox-plan; a repo with no STATE.md; a repo whose last commit is 30 days old, so the two definitions give different numbers; a repo with a plan and no commit. Rebuilt from this tree and run against the full suite: 16 of 16 mutants now fail it. The same fixtures exposed two defects, fixed here: - --inbox-plan took neste as ONE field and cut the prose at its first '|' (also in 0.34.0); it now takes that field onward. - a symlinked PLAN.md was aged by the link's own mtime; it now uses stat -L, so the plan's age is the target's. Docs: CHANGELOG no longer says "field 17 onward" (the index is 18) and now records the no-STATE.md record fix and the --inbox-plan fix; README's requirement says macOS, since board.sh uses BSD stat and renders nothing under GNU stat. board-selftest 461 -> 478 (badge 978). Suites: coord 257, board 478, route 73, orders 116, guard 54; npm test 12/12, run after git add. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
87fb78334e
commit
6f4908a5dc
5 changed files with 145 additions and 15 deletions
|
|
@ -3483,7 +3483,7 @@ pc_state() {
|
|||
echo "# STATE - $2"
|
||||
echo "## NESTE - START HER"
|
||||
echo "<!-- board: status=$3; blocked-on=-; next-cost=Sonnet 5/high -->"
|
||||
echo "Next step for $2."
|
||||
echo "${4:-Next step for $2.}"
|
||||
} > "$1/STATE.md"
|
||||
}
|
||||
# pc_commit_at <dir> <epoch> <msg>: commit everything with a fixed committer date.
|
||||
|
|
@ -3524,7 +3524,14 @@ pc_touch_at "$PC_ROOT/p-fresh/PLAN.md" "$PC_NOW"
|
|||
|
||||
# p-stale: PLAN.md 5 days and 3 hours older than the last commit -> 5d. Its
|
||||
# content looks like a value on purpose ("PLAN=99d"); it must not be read.
|
||||
mkrepo "$PC_ROOT/p-stale"; pc_state "$PC_ROOT/p-stale" p-stale planned
|
||||
# Its NESTE carries a literal '|' and it holds one unhandled message, so the
|
||||
# same repo pins where every "last field onward" reader starts AND that it
|
||||
# really reads onward (section 8 below).
|
||||
mkrepo "$PC_ROOT/p-stale"
|
||||
pc_state "$PC_ROOT/p-stale" p-stale planned "Next step for p-stale | then the rest."
|
||||
mkdir -p "$PC_COORD/p-stale/inbox"
|
||||
printf -- '---\nfrom: x\nto: p-stale\nsubject: s\nreply-expected: yes\n---\nm\n' \
|
||||
> "$PC_COORD/p-stale/inbox/20260901T101010Z-1-from-x.md"
|
||||
printf '# PLAN\nPLAN=99d\n' > "$PC_ROOT/p-stale/PLAN.md"
|
||||
PC_P_STALE_CT=$((PC_NOW - 3600))
|
||||
pc_commit_at "$PC_ROOT/p-stale" "$PC_P_STALE_CT" init
|
||||
|
|
@ -3544,6 +3551,46 @@ mkrepo "$PC_ROOT/p-lower"; pc_state "$PC_ROOT/p-lower" p-lower planned
|
|||
echo "# plan" > "$PC_ROOT/p-lower/plan.md"
|
||||
pc_commit_at "$PC_ROOT/p-lower" $((PC_NOW - PC_DAY)) init
|
||||
|
||||
# The next four fixtures exist because an independent review ran 16 mutants of
|
||||
# the column against this suite and 5 survived. Each fixture below is the one
|
||||
# a surviving mutant could not get past.
|
||||
|
||||
# p-nostate: a repo with NO STATE.md. Its record is written by a separate
|
||||
# printf, which is exactly where a field was once missing (0.34.0 printed
|
||||
# voy=(ingen STATE.md) and an empty neste=), so a short record must show here.
|
||||
# The last commit is 40 days old.
|
||||
mkrepo "$PC_ROOT/p-nostate"
|
||||
: > "$PC_ROOT/p-nostate/PLAN.md"
|
||||
PC_NS_CT=$((PC_NOW - 40 * PC_DAY))
|
||||
pc_commit_at "$PC_ROOT/p-nostate" "$PC_NS_CT" init
|
||||
pc_touch_at "$PC_ROOT/p-nostate/PLAN.md" $((PC_NS_CT - 3 * PC_DAY - 3600))
|
||||
|
||||
# p-old: the column's DEFINITION. The last commit is 30 days old, so "days
|
||||
# behind the last commit" (10) and "days behind now" (40) are different
|
||||
# numbers; every fixture above has a commit close enough to now that the two
|
||||
# readings coincide.
|
||||
mkrepo "$PC_ROOT/p-old"; pc_state "$PC_ROOT/p-old" p-old planned
|
||||
: > "$PC_ROOT/p-old/PLAN.md"
|
||||
PC_OLD_CT=$((PC_NOW - 30 * PC_DAY))
|
||||
pc_commit_at "$PC_ROOT/p-old" "$PC_OLD_CT" init
|
||||
pc_touch_at "$PC_ROOT/p-old/PLAN.md" $((PC_OLD_CT - 10 * PC_DAY - 5 * 3600))
|
||||
|
||||
# p-nocommit: a plan and no commit at all. There is nothing to lag behind, so
|
||||
# the honest cell is '?' - never '-', which would claim there is no plan.
|
||||
mkrepo "$PC_ROOT/p-nocommit"; pc_state "$PC_ROOT/p-nocommit" p-nocommit planned
|
||||
: > "$PC_ROOT/p-nocommit/PLAN.md"
|
||||
|
||||
# p-link: PLAN.md is a symlink. The cell must read the PLAN's age, i.e. the
|
||||
# target's mtime; the link's own mtime is when the link was made, and reading
|
||||
# it turns an 8-day-old plan into 0d.
|
||||
mkrepo "$PC_ROOT/p-link"; pc_state "$PC_ROOT/p-link" p-link planned
|
||||
mkdir -p "$PC_ROOT/p-link/docs"; echo "# PLAN" > "$PC_ROOT/p-link/docs/real-plan.md"
|
||||
ln -s docs/real-plan.md "$PC_ROOT/p-link/PLAN.md"
|
||||
PC_LINK_CT=$((PC_NOW - 2 * 3600))
|
||||
pc_commit_at "$PC_ROOT/p-link" "$PC_LINK_CT" init
|
||||
pc_touch_at "$PC_ROOT/p-link/docs/real-plan.md" $((PC_LINK_CT - 8 * PC_DAY - 3600))
|
||||
touch -h "$PC_ROOT/p-link/PLAN.md"
|
||||
|
||||
# --- Ground truth for the fixtures (these must be green today) -------------
|
||||
[ -z "$(git -C "$PC_ROOT/p-stale" status --porcelain)" ]
|
||||
check "plan: fixture - p-stale is committed clean" $?
|
||||
|
|
@ -3559,7 +3606,7 @@ ls -1 "$PC_ROOT/p-lower" | grep -qx 'PLAN.md'; PC_rc=$?
|
|||
|
||||
PC_TABLE="$(pc_board)"
|
||||
PC_N_REPOS="$(printf '%s\n' "$PC_TABLE" | sed -n 's/^BOARD .*(\([0-9][0-9]*\) repo).*/\1/p' | head -1)"
|
||||
[ "${PC_N_REPOS:-0}" -eq 5 ]; check "plan: fixture - board scanned the 5 fixture repos (header says ${PC_N_REPOS:-nothing})" $?
|
||||
[ "${PC_N_REPOS:-0}" -eq 9 ]; check "plan: fixture - board scanned the 9 fixture repos (header says ${PC_N_REPOS:-nothing})" $?
|
||||
|
||||
# --- 1. Three different values from three repos ----------------------------
|
||||
printf '%s\n' "$PC_TABLE" | grep -q '^REPO .* PLAN '
|
||||
|
|
@ -3577,7 +3624,7 @@ check "plan 1: the three fixtures show three DIFFERENT values ($PC_V3)" $?
|
|||
[ "$(pc_table_cell "$PC_TABLE" p-lower)" = "-" ]; check "plan 2: lowercase plan.md in the root -> '-' (byte-exact name)" $?
|
||||
|
||||
# --- 3. --row carries plan= with the table's value ---------------------------
|
||||
for PC_r in p-none p-fresh p-stale p-docs p-lower; do
|
||||
for PC_r in p-none p-fresh p-stale p-docs p-lower p-nostate p-old p-nocommit p-link; do
|
||||
PC_RV="$(pc_row_plan "$(pc_board --row "$PC_r")")"
|
||||
PC_TV="$(pc_table_cell "$PC_TABLE" "$PC_r")"
|
||||
[ -n "$PC_RV" ] && [ "$PC_RV" = "$PC_TV" ]
|
||||
|
|
@ -3645,7 +3692,7 @@ done
|
|||
|
||||
# --- 6. Denominator: one value per scanned repo ------------------------------
|
||||
PC_WITH=0
|
||||
for PC_r in p-none p-fresh p-stale p-docs p-lower; do
|
||||
for PC_r in p-none p-fresh p-stale p-docs p-lower p-nostate p-old p-nocommit p-link; do
|
||||
[ -n "$(pc_table_cell "$PC_TABLE" "$PC_r")" ] && PC_WITH=$((PC_WITH + 1))
|
||||
done
|
||||
# A non-empty, non-zero denominator first: with an empty scan both sides are 0
|
||||
|
|
@ -3665,6 +3712,55 @@ check "plan 7: the legend says touch/checkout reset the mtime" $?
|
|||
if printf '%s' "$PC_LEG" | LC_ALL=C grep -q '[^ -~]'; then PC_rc=1; else PC_rc=0; fi
|
||||
[ -n "$PC_LEG" ] && [ "$PC_rc" -eq 0 ]; check "plan 7: the legend is ASCII like the rest of the table" $?
|
||||
|
||||
# --- 8. What the surviving mutants got past --------------------------------
|
||||
# neste= start, pinned EXACTLY in the two renderings that take "the last field
|
||||
# onward" besides --dispatch (which has its own check in section 18). A field
|
||||
# inserted before `neste` with an index left behind shows up as a prefix
|
||||
# ("5d|Next step ..."), and a reader that takes ONE field instead of "onward"
|
||||
# cuts the prose at its first '|'.
|
||||
PC_NESTE='Next step for p-stale | then the rest.'
|
||||
pc_board --row p-stale | grep -qxF "neste=$PC_NESTE"
|
||||
check "plan 8: --row neste= is the NESTE prose exactly, '|' included" $?
|
||||
PC_IP="$(pc_board --inbox-plan)"
|
||||
printf '%s\n' "$PC_IP" | grep -qx 'repo=p-stale'
|
||||
check "plan 8: fixture - --inbox-plan has a block for p-stale" $?
|
||||
printf '%s\n' "$PC_IP" | awk 'BEGIN{RS=""} /(^|\n)repo=p-stale(\n|$)/' | grep -qxF "neste=$PC_NESTE"
|
||||
check "plan 8: --inbox-plan neste= is the NESTE prose exactly, '|' included" $?
|
||||
|
||||
# A repo with no STATE.md still gets its measured value, and its neste= is the
|
||||
# placeholder rather than an empty line or a value shifted from another field.
|
||||
PC_NS_EXP="$(( (PC_NS_CT - $(pc_mtime "$PC_ROOT/p-nostate/PLAN.md")) / PC_DAY ))d"
|
||||
PC_NS_ROW="$(pc_board --row p-nostate)"
|
||||
printf '%s\n' "$PC_NS_ROW" | grep -qx "plan=$PC_NS_EXP"
|
||||
check "plan 8: no STATE.md - --row plan= is the measured value ($PC_NS_EXP)" $?
|
||||
printf '%s\n' "$PC_NS_ROW" | grep -qxF 'neste=(ingen STATE.md)'
|
||||
check "plan 8: no STATE.md - --row neste= is the placeholder, not empty or shifted" $?
|
||||
[ "$(pc_table_cell "$PC_TABLE" p-nostate)" = "$PC_NS_EXP" ]
|
||||
check "plan 8: no STATE.md - the table cell is the measured value too" $?
|
||||
|
||||
# The definition: behind the LAST COMMIT, not behind now.
|
||||
PC_OLD_EXP="$(( (PC_OLD_CT - $(pc_mtime "$PC_ROOT/p-old/PLAN.md")) / PC_DAY ))d"
|
||||
PC_OLD_NOW="$(( (PC_NOW - $(pc_mtime "$PC_ROOT/p-old/PLAN.md")) / PC_DAY ))d"
|
||||
[ "$PC_OLD_EXP" != "$PC_OLD_NOW" ]
|
||||
check "plan 8: fixture - p-old separates 'behind commit' ($PC_OLD_EXP) from 'behind now' ($PC_OLD_NOW)" $?
|
||||
[ "$(pc_table_cell "$PC_TABLE" p-old)" = "$PC_OLD_EXP" ]
|
||||
check "plan 8: Nd counts days behind the LAST COMMIT, not behind now ($PC_OLD_EXP)" $?
|
||||
|
||||
# No commit: '?' in both renderings.
|
||||
git -C "$PC_ROOT/p-nocommit" log -1 >/dev/null 2>&1
|
||||
[ $? -ne 0 ]; check "plan 8: fixture - p-nocommit really has no commit" $?
|
||||
[ "$(pc_table_cell "$PC_TABLE" p-nocommit)" = "?" ]
|
||||
check "plan 8: a plan with no commit reads '?', never '-'" $?
|
||||
pc_board --row p-nocommit | grep -qxF 'plan=?'
|
||||
check "plan 8: --row carries the same '?'" $?
|
||||
|
||||
# Symlink: the target's age, not the link's.
|
||||
PC_LINK_EXP="$(( (PC_LINK_CT - $(pc_mtime "$PC_ROOT/p-link/docs/real-plan.md")) / PC_DAY ))d"
|
||||
[ "$(stat -f %m "$PC_ROOT/p-link/PLAN.md")" -ge "$PC_LINK_CT" ] && [ "$PC_LINK_EXP" != "0d" ]
|
||||
check "plan 8: fixture - the link itself is newer than the commit, its target is $PC_LINK_EXP behind" $?
|
||||
[ "$(pc_table_cell "$PC_TABLE" p-link)" = "$PC_LINK_EXP" ]
|
||||
check "plan 8: a symlinked PLAN.md reads the TARGET's age ($PC_LINK_EXP), not the link's" $?
|
||||
|
||||
/bin/rm -rf "$PC_ROOT" "$PC_COORD" 2>/dev/null
|
||||
|
||||
echo ""
|
||||
|
|
|
|||
|
|
@ -838,7 +838,9 @@ printf '%s\n' "$REPOS" | while IFS= read -r d; do
|
|||
plancol="-"
|
||||
for pl_f in "$d"/PLAN.m[d]; do
|
||||
[ "${pl_f##*/}" = "PLAN.md" ] && [ -f "$pl_f" ] || continue
|
||||
pl_m="$(stat -f %m "$pl_f" 2>/dev/null)"
|
||||
# -L: the PLAN's age is the target's mtime; a symlink's own mtime is only
|
||||
# when the link was made.
|
||||
pl_m="$(stat -L -f %m "$pl_f" 2>/dev/null)"
|
||||
if [ -z "$pl_m" ] || [ -z "$lastct" ]; then
|
||||
plancol="?"
|
||||
elif [ "$pl_m" -ge "$lastct" ]; then
|
||||
|
|
@ -1982,7 +1984,11 @@ inbox_plan() {
|
|||
FILENAME==RCF {
|
||||
name = $3
|
||||
rc_bucket[name] = $1; rc_status[name] = $4; rc_cost[name] = $5
|
||||
# neste is the LAST field and may itself contain a pipe: take field 18
|
||||
# ONWARD, never field 18 alone - a single field cuts the prose at its
|
||||
# first pipe. The index moves with the record.
|
||||
rc_dir[name] = $10; rc_neste[name] = $18
|
||||
for (i = 19; i <= NF; i++) rc_neste[name] = rc_neste[name] "|" $i
|
||||
next
|
||||
}
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue