Snapshot and restore a template, so an improvement can actually be attributed

Learning rewrites the template in place, which means a rate that climbs over an
evening has three explanations and the numbers cannot tell them apart: the
template got better, the sensor got wiped clean, or the user learned where the
sensor likes to be pressed. Jorijn named the second and third while the numbers
were still going up. All three move the same way on the same time axis, and the
first trend run had no way to separate them because no earlier version of the
template survived.

A snapshot makes the paired test possible. Measure the learned template, restore
the older one, measure again within the same session -- the sensor is equally
clean and the user equally practised across both halves, so the only thing that
differs is the template. A rate that falls back on restore is learning. A rate
that stays up is not.

Restore stops the daemon before swapping the files and brings it back with
learning off, because the trustlet caches the template in memory once loaded and
because a restored template that immediately starts learning again is not a
control.
This commit is contained in:
Jorijn van der Graaf 2026-09-04 23:49:25 +02:00
commit f3da01a511

View file

@ -2,12 +2,26 @@
# fplearn.sh -- the template-learning measurement, as a protocol rather than a
# pile of remembered commands.
#
# fplearn.sh snapshot [name] save the current template aside
# fplearn.sh restore <name> put a saved template back and reload it
# fplearn.sh wipe remove every stored template (backup first)
# fplearn.sh enrol [finger] enrol at the config's sample count
# fplearn.sh base [n] [w] trial with learning OFF (the baseline)
# fplearn.sh trend [n] [w] three trials with learning ON
# fplearn.sh sizes just print the template container sizes
#
# SNAPSHOT BEFORE EVERY MEASUREMENT BLOCK. Learning rewrites the template in
# place, so without a snapshot an improvement cannot be attributed: a rate that
# climbs over an evening is equally explained by the template getting better, by
# the SENSOR being wiped clean, or by the USER learning where the sensor likes
# to be pressed (Jorijn, 2026-09-04, having spotted both while the numbers were
# still going up). All three move the same way on the same time axis.
#
# A snapshot makes the paired test possible: measure the learned template, then
# restore the older one and measure again WITHIN THE SAME SESSION, so the sensor
# is equally clean and the user equally practised for both halves. A rate that
# falls back on restore is learning. A rate that stays up is not.
#
# WIPE FIRST when re-enrolling a finger that is already in the group. Measured
# 2026-09-04: the duplicated-finger check refuses a finger the group already
# holds -- 0 accepted of 7 presses, rc=0 on every one, while a never-enrolled
@ -76,7 +90,46 @@ restart() { # $1 = extra args
printf ' TIMED OUT\n'; return 1
}
SNAPDIR=$HOME/fp6-backups/snapshots
case "${1:-}" in
snapshot)
NAME=${2:-$(date +%Y%m%d-%H%M%S)}
D=$SNAPDIR/$NAME
mkdir -p "$D"
n=0
for f in $(sudo ls "$GROUP"); do
sz=$(sudo stat -c %s "$GROUP/$f")
if [ "$sz" -gt 200000 ]; then sudo cp -p "$GROUP/$f" "$D/$f"; n=$((n+1)); fi
done
sudo cp -p "$MAP" "$D/" 2>/dev/null || true
sudo chown -R "$(id -u):$(id -g)" "$D"
echo "snapshot '$NAME': $n container(s)"
ls -la "$D" | awk 'NR>3{printf " %9d %s\n", $5, $9}'
echo "restore with: fplearn.sh restore $NAME" ;;
restore)
NAME=${2:-}
D=$SNAPDIR/$NAME
[ -n "$NAME" ] && [ -d "$D" ] || { echo "usage: fplearn.sh restore <name>"; echo "available:"; ls "$SNAPDIR" 2>/dev/null | sed 's/^/ /'; exit 1; }
echo "=== restore snapshot '$NAME' ==="
echo "before:"; sizes
# The trustlet holds the template in memory once loaded, so a restore that
# does not restart the daemon changes the file and nothing else.
sudo systemctl stop "$UNIT" 2>/dev/null; sleep 2
for f in $(ls "$D"); do
case "$f" in fingers-*.map) sudo cp -p "$D/$f" "$MAP" ;;
*) sudo cp -p "$D/$f" "$GROUP/$f" ;; esac
done
sudo sync
restart "--learn=0" || exit 1
echo "after:"; sizes
fprintd-list user 2>&1 | tail -1
echo
echo "Daemon is up with learning OFF, so the restored template stays put."
echo "Measure it now, in this session, against the block you just ran:"
echo " fplearn.sh base" ;;
sizes)
echo "template containers now:"; sizes ;;
@ -156,5 +209,5 @@ trend)
echo "does not is noise, and the daemon's own 'learn:' lines say which." ;;
*)
sed -n '2,38p' "$0"; exit 1 ;;
sed -n '2,52p' "$0"; exit 1 ;;
esac