From f3da01a511c0de0ad65ecbd57f46395bc569ddfa Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Fri, 4 Sep 2026 23:49:25 +0200 Subject: [PATCH] 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. --- packaging/fplearn.sh | 55 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/packaging/fplearn.sh b/packaging/fplearn.sh index 7c3ae9a..ebc4032 100755 --- a/packaging/fplearn.sh +++ b/packaging/fplearn.sh @@ -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 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 "; 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