Threshold at 1.5x doubles the tap rate; add coverage-guided enrolment
The threshold change is the first thing to move accuracy. Labelled protocol,
enrolled quick taps: 4 of 10, against 2 of 10 for every previous build. Seven
of fifteen presses now get two or more frames where none did before, and the
landing frames the old threshold discarded turn up in the transcript at 207,
213, 242 and 284. Wrong finger still 0 of 5.
It also explains the latency asymmetry Jorijn noticed. A match ends the loop
the moment it happens, mean 1317 ms. A no-match waits for the finger to lift,
mean 2190 ms, because a later frame in the same press may still match -- and
they do, at frames 3, 5 and 8. That is the press rule working, not a fault.
What the same run says about the template is worse than the loop ever was. One
press produced eight frames at full contact, 362 to 367, and every one
rejected; another produced six. Roughly one frame in seven matches, against the
47 to 75 percent the journal records for the template the research harness
enrolled. The first template here was ten quick taps in about one position, so
the algorithm was handed ten near-duplicate images of one spot.
fpenrol.sh enrols with a different contact position per ACCEPTED sample --
centre, left, right, tip, joint, rolled either way -- driven by
fprintd-enroll's own per-stage output rather than by counting presses. Enrol as
a SECOND finger so both templates coexist and the comparison holds the loop
constant; the trustlet reports which fid matched, and the daemon's map turns
that back into a name.
2026-09-03 00:20:34 +02:00
|
|
|
#!/bin/sh
|
|
|
|
|
# fpenrol.sh -- enrol a finger with COVERAGE guidance.
|
|
|
|
|
#
|
|
|
|
|
# fpenrol.sh [finger_name] default right-middle-finger
|
|
|
|
|
#
|
|
|
|
|
# The first template on this device was enrolled from ten quick taps in
|
|
|
|
|
# roughly one position, and it matches roughly one frame in seven -- against
|
|
|
|
|
# 47-75% for the template the research harness enrolled. The algorithm was
|
|
|
|
|
# given ten near-duplicate images of one spot, so it recognises that spot and
|
2026-09-03 17:44:35 +02:00
|
|
|
# little else.
|
Threshold at 1.5x doubles the tap rate; add coverage-guided enrolment
The threshold change is the first thing to move accuracy. Labelled protocol,
enrolled quick taps: 4 of 10, against 2 of 10 for every previous build. Seven
of fifteen presses now get two or more frames where none did before, and the
landing frames the old threshold discarded turn up in the transcript at 207,
213, 242 and 284. Wrong finger still 0 of 5.
It also explains the latency asymmetry Jorijn noticed. A match ends the loop
the moment it happens, mean 1317 ms. A no-match waits for the finger to lift,
mean 2190 ms, because a later frame in the same press may still match -- and
they do, at frames 3, 5 and 8. That is the press rule working, not a fault.
What the same run says about the template is worse than the loop ever was. One
press produced eight frames at full contact, 362 to 367, and every one
rejected; another produced six. Roughly one frame in seven matches, against the
47 to 75 percent the journal records for the template the research harness
enrolled. The first template here was ten quick taps in about one position, so
the algorithm was handed ten near-duplicate images of one spot.
fpenrol.sh enrols with a different contact position per ACCEPTED sample --
centre, left, right, tip, joint, rolled either way -- driven by
fprintd-enroll's own per-stage output rather than by counting presses. Enrol as
a SECOND finger so both templates coexist and the comparison holds the loop
constant; the trustlet reports which fid matched, and the daemon's map turns
that back into a name.
2026-09-03 00:20:34 +02:00
|
|
|
#
|
|
|
|
|
# This walks a different contact position per accepted sample. It reads
|
|
|
|
|
# fprintd-enroll's per-stage output and prompts the next position as each
|
|
|
|
|
# stage passes, so the guidance tracks what the trustlet ACCEPTED rather than
|
|
|
|
|
# how many times you pressed.
|
2026-09-03 17:44:35 +02:00
|
|
|
#
|
|
|
|
|
# TWO BUGS FIXED 2026-09-03, both of which had silently disabled a feature
|
|
|
|
|
# this script claims to provide:
|
|
|
|
|
#
|
|
|
|
|
# 1. `pos()` was `eval "printf '%s' \"\$$1\""` over the script's positional
|
|
|
|
|
# parameters. Inside a FUNCTION, `$1` is the function's own argument, so
|
|
|
|
|
# `pos 3` printed "3" and `pos 10` printed `${1}0` = "100". Every run this
|
|
|
|
|
# script ever drove -- including the one that produced the 7/10 template --
|
|
|
|
|
# printed sample numbers where positions should have been, so NO enrolment
|
|
|
|
|
# has ever actually received position guidance. The spread in those
|
|
|
|
|
# templates came from the config's overlap band refusing near-duplicates,
|
|
|
|
|
# not from anything this script said. Positions now live in a newline
|
|
|
|
|
# list indexed with sed, which has no interaction with $1 at all.
|
|
|
|
|
#
|
|
|
|
|
# 2. The sample count was hardcoded to 20 while the daemon was configured for
|
|
|
|
|
# 30, so the counter froze at 20/20 and the run looked like it had hung or
|
|
|
|
|
# been clamped. It had not: all 30 samples were taken. The count now comes
|
|
|
|
|
# from the daemon's own num-enroll-stages property, which it reads from the
|
|
|
|
|
# same config the trustlet is given.
|
Threshold at 1.5x doubles the tap rate; add coverage-guided enrolment
The threshold change is the first thing to move accuracy. Labelled protocol,
enrolled quick taps: 4 of 10, against 2 of 10 for every previous build. Seven
of fifteen presses now get two or more frames where none did before, and the
landing frames the old threshold discarded turn up in the transcript at 207,
213, 242 and 284. Wrong finger still 0 of 5.
It also explains the latency asymmetry Jorijn noticed. A match ends the loop
the moment it happens, mean 1317 ms. A no-match waits for the finger to lift,
mean 2190 ms, because a later frame in the same press may still match -- and
they do, at frames 3, 5 and 8. That is the press rule working, not a fault.
What the same run says about the template is worse than the loop ever was. One
press produced eight frames at full contact, 362 to 367, and every one
rejected; another produced six. Roughly one frame in seven matches, against the
47 to 75 percent the journal records for the template the research harness
enrolled. The first template here was ten quick taps in about one position, so
the algorithm was handed ten near-duplicate images of one spot.
fpenrol.sh enrols with a different contact position per ACCEPTED sample --
centre, left, right, tip, joint, rolled either way -- driven by
fprintd-enroll's own per-stage output rather than by counting presses. Enrol as
a SECOND finger so both templates coexist and the comparison holds the loop
constant; the trustlet reports which fid matched, and the daemon's map turns
that back into a name.
2026-09-03 00:20:34 +02:00
|
|
|
F=${1:-right-middle-finger}
|
2026-09-03 17:44:35 +02:00
|
|
|
|
|
|
|
|
# Position prompts are OPT-IN: FPENROL_GUIDE=1. The one template that verified
|
|
|
|
|
# well (right-middle, 20 samples, 7/10 quick taps) was enrolled with NO prompts
|
|
|
|
|
# -- the pos() bug meant none were ever shown -- and the algorithm's own
|
|
|
|
|
# overlap band did the spreading. The first run where prompts actually fired
|
|
|
|
|
# (right-middle, 30 samples, edges/tips/rolled-hard) needed 74 presses for 30
|
|
|
|
|
# accepts and then matched 0/10. Prompting a user toward positions they never
|
|
|
|
|
# use in a real tap builds a template of positions they never use in a real
|
|
|
|
|
# tap. Without prompts, the instruction is the one that worked: press the way
|
|
|
|
|
# you would to unlock, and let the REFUSED messages move you.
|
|
|
|
|
GUIDE=${FPENROL_GUIDE:-0}
|
|
|
|
|
|
|
|
|
|
# The daemon is the authority on how many stages there are.
|
|
|
|
|
STAGES=$(busctl get-property net.reactivated.Fprint \
|
|
|
|
|
/net/reactivated/Fprint/Device/0 \
|
|
|
|
|
net.reactivated.Fprint.Device num-enroll-stages 2>/dev/null \
|
|
|
|
|
| awk '{print $2}')
|
|
|
|
|
case "$STAGES" in
|
|
|
|
|
''|*[!0-9]*) STAGES=20
|
|
|
|
|
echo "warning: could not read num-enroll-stages; assuming $STAGES" ;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
POSITIONS='centre of the pad
|
|
|
|
|
slightly LEFT of centre
|
|
|
|
|
slightly RIGHT of centre
|
|
|
|
|
higher up, toward the TIP
|
|
|
|
|
lower down, toward the JOINT
|
|
|
|
|
centre, rolled LEFT
|
|
|
|
|
centre, rolled RIGHT
|
|
|
|
|
tip, rolled slightly left
|
|
|
|
|
joint, rolled slightly right
|
|
|
|
|
centre, a little firmer
|
|
|
|
|
far LEFT edge of the pad
|
|
|
|
|
far RIGHT edge of the pad
|
|
|
|
|
very tip of the finger
|
|
|
|
|
well down toward the joint
|
|
|
|
|
upper left of the pad
|
|
|
|
|
upper right of the pad
|
|
|
|
|
lower left of the pad
|
|
|
|
|
lower right of the pad
|
|
|
|
|
centre, rolled hard left
|
|
|
|
|
centre, rolled hard right'
|
|
|
|
|
NPOS=$(printf '%s\n' "$POSITIONS" | wc -l)
|
|
|
|
|
|
|
|
|
|
# More samples than positions is expected at 30. Cycle, and say so, rather
|
|
|
|
|
# than printing nothing -- printing nothing is what hid bug 1 for two sessions.
|
|
|
|
|
pos() {
|
|
|
|
|
n=$(( ($1 - 1) % NPOS + 1 ))
|
|
|
|
|
printf '%s' "$(printf '%s\n' "$POSITIONS" | sed -n "${n}p")"
|
|
|
|
|
[ "$1" -gt "$NPOS" ] && printf ' (again, press slightly differently)'
|
|
|
|
|
}
|
|
|
|
|
|
Threshold at 1.5x doubles the tap rate; add coverage-guided enrolment
The threshold change is the first thing to move accuracy. Labelled protocol,
enrolled quick taps: 4 of 10, against 2 of 10 for every previous build. Seven
of fifteen presses now get two or more frames where none did before, and the
landing frames the old threshold discarded turn up in the transcript at 207,
213, 242 and 284. Wrong finger still 0 of 5.
It also explains the latency asymmetry Jorijn noticed. A match ends the loop
the moment it happens, mean 1317 ms. A no-match waits for the finger to lift,
mean 2190 ms, because a later frame in the same press may still match -- and
they do, at frames 3, 5 and 8. That is the press rule working, not a fault.
What the same run says about the template is worse than the loop ever was. One
press produced eight frames at full contact, 362 to 367, and every one
rejected; another produced six. Roughly one frame in seven matches, against the
47 to 75 percent the journal records for the template the research harness
enrolled. The first template here was ten quick taps in about one position, so
the algorithm was handed ten near-duplicate images of one spot.
fpenrol.sh enrols with a different contact position per ACCEPTED sample --
centre, left, right, tip, joint, rolled either way -- driven by
fprintd-enroll's own per-stage output rather than by counting presses. Enrol as
a SECOND finger so both templates coexist and the comparison holds the loop
constant; the trustlet reports which fid matched, and the daemon's map turns
that back into a name.
2026-09-03 00:20:34 +02:00
|
|
|
i=1
|
2026-09-03 17:44:35 +02:00
|
|
|
if [ "$GUIDE" = 1 ]; then
|
|
|
|
|
echo "enrolling $F with position guidance -- $STAGES samples (from the daemon)"
|
|
|
|
|
echo "press FLAT and firm, hold about a second, then LIFT fully."
|
|
|
|
|
prompt() { echo ">>> sample $1/$STAGES: $(pos $1)"; }
|
|
|
|
|
else
|
|
|
|
|
echo "enrolling $F -- $STAGES samples (from the daemon), NO position prompts"
|
|
|
|
|
echo "press the way you would to UNLOCK the phone. When a sample is REFUSED,"
|
|
|
|
|
echo "shift a little from where you were; otherwise do not think about it."
|
|
|
|
|
prompt() { echo ">>> sample $1/$STAGES"; }
|
|
|
|
|
fi
|
Threshold at 1.5x doubles the tap rate; add coverage-guided enrolment
The threshold change is the first thing to move accuracy. Labelled protocol,
enrolled quick taps: 4 of 10, against 2 of 10 for every previous build. Seven
of fifteen presses now get two or more frames where none did before, and the
landing frames the old threshold discarded turn up in the transcript at 207,
213, 242 and 284. Wrong finger still 0 of 5.
It also explains the latency asymmetry Jorijn noticed. A match ends the loop
the moment it happens, mean 1317 ms. A no-match waits for the finger to lift,
mean 2190 ms, because a later frame in the same press may still match -- and
they do, at frames 3, 5 and 8. That is the press rule working, not a fault.
What the same run says about the template is worse than the loop ever was. One
press produced eight frames at full contact, 362 to 367, and every one
rejected; another produced six. Roughly one frame in seven matches, against the
47 to 75 percent the journal records for the template the research harness
enrolled. The first template here was ten quick taps in about one position, so
the algorithm was handed ten near-duplicate images of one spot.
fpenrol.sh enrols with a different contact position per ACCEPTED sample --
centre, left, right, tip, joint, rolled either way -- driven by
fprintd-enroll's own per-stage output rather than by counting presses. Enrol as
a SECOND finger so both templates coexist and the comparison holds the loop
constant; the trustlet reports which fid matched, and the daemon's map turns
that back into a name.
2026-09-03 00:20:34 +02:00
|
|
|
echo
|
2026-09-03 17:44:35 +02:00
|
|
|
prompt 1
|
Threshold at 1.5x doubles the tap rate; add coverage-guided enrolment
The threshold change is the first thing to move accuracy. Labelled protocol,
enrolled quick taps: 4 of 10, against 2 of 10 for every previous build. Seven
of fifteen presses now get two or more frames where none did before, and the
landing frames the old threshold discarded turn up in the transcript at 207,
213, 242 and 284. Wrong finger still 0 of 5.
It also explains the latency asymmetry Jorijn noticed. A match ends the loop
the moment it happens, mean 1317 ms. A no-match waits for the finger to lift,
mean 2190 ms, because a later frame in the same press may still match -- and
they do, at frames 3, 5 and 8. That is the press rule working, not a fault.
What the same run says about the template is worse than the loop ever was. One
press produced eight frames at full contact, 362 to 367, and every one
rejected; another produced six. Roughly one frame in seven matches, against the
47 to 75 percent the journal records for the template the research harness
enrolled. The first template here was ten quick taps in about one position, so
the algorithm was handed ten near-duplicate images of one spot.
fpenrol.sh enrols with a different contact position per ACCEPTED sample --
centre, left, right, tip, joint, rolled either way -- driven by
fprintd-enroll's own per-stage output rather than by counting presses. Enrol as
a SECOND finger so both templates coexist and the comparison holds the loop
constant; the trustlet reports which fid matched, and the daemon's map turns
that back into a name.
2026-09-03 00:20:34 +02:00
|
|
|
fprintd-enroll -f "$F" user 2>&1 | while IFS= read -r line; do
|
|
|
|
|
case "$line" in
|
|
|
|
|
*enroll-stage-passed*)
|
|
|
|
|
i=$((i+1))
|
2026-09-03 17:44:35 +02:00
|
|
|
if [ "$i" -le "$STAGES" ]; then
|
|
|
|
|
echo " accepted."
|
|
|
|
|
prompt "$i"
|
|
|
|
|
else
|
Threshold at 1.5x doubles the tap rate; add coverage-guided enrolment
The threshold change is the first thing to move accuracy. Labelled protocol,
enrolled quick taps: 4 of 10, against 2 of 10 for every previous build. Seven
of fifteen presses now get two or more frames where none did before, and the
landing frames the old threshold discarded turn up in the transcript at 207,
213, 242 and 284. Wrong finger still 0 of 5.
It also explains the latency asymmetry Jorijn noticed. A match ends the loop
the moment it happens, mean 1317 ms. A no-match waits for the finger to lift,
mean 2190 ms, because a later frame in the same press may still match -- and
they do, at frames 3, 5 and 8. That is the press rule working, not a fault.
What the same run says about the template is worse than the loop ever was. One
press produced eight frames at full contact, 362 to 367, and every one
rejected; another produced six. Roughly one frame in seven matches, against the
47 to 75 percent the journal records for the template the research harness
enrolled. The first template here was ten quick taps in about one position, so
the algorithm was handed ten near-duplicate images of one spot.
fpenrol.sh enrols with a different contact position per ACCEPTED sample --
centre, left, right, tip, joint, rolled either way -- driven by
fprintd-enroll's own per-stage output rather than by counting presses. Enrol as
a SECOND finger so both templates coexist and the comparison holds the loop
constant; the trustlet reports which fid matched, and the daemon's map turns
that back into a name.
2026-09-03 00:20:34 +02:00
|
|
|
echo " accepted."
|
|
|
|
|
fi ;;
|
2026-09-03 00:26:14 +02:00
|
|
|
*enroll-retry-scan*) echo " REFUSED -- move further from the last position, or press flatter" ;;
|
Threshold at 1.5x doubles the tap rate; add coverage-guided enrolment
The threshold change is the first thing to move accuracy. Labelled protocol,
enrolled quick taps: 4 of 10, against 2 of 10 for every previous build. Seven
of fifteen presses now get two or more frames where none did before, and the
landing frames the old threshold discarded turn up in the transcript at 207,
213, 242 and 284. Wrong finger still 0 of 5.
It also explains the latency asymmetry Jorijn noticed. A match ends the loop
the moment it happens, mean 1317 ms. A no-match waits for the finger to lift,
mean 2190 ms, because a later frame in the same press may still match -- and
they do, at frames 3, 5 and 8. That is the press rule working, not a fault.
What the same run says about the template is worse than the loop ever was. One
press produced eight frames at full contact, 362 to 367, and every one
rejected; another produced six. Roughly one frame in seven matches, against the
47 to 75 percent the journal records for the template the research harness
enrolled. The first template here was ten quick taps in about one position, so
the algorithm was handed ten near-duplicate images of one spot.
fpenrol.sh enrols with a different contact position per ACCEPTED sample --
centre, left, right, tip, joint, rolled either way -- driven by
fprintd-enroll's own per-stage output rather than by counting presses. Enrol as
a SECOND finger so both templates coexist and the comparison holds the loop
constant; the trustlet reports which fid matched, and the daemon's map turns
that back into a name.
2026-09-03 00:20:34 +02:00
|
|
|
*enroll-completed*) echo; echo "COMPLETED." ;;
|
|
|
|
|
*enroll-failed*) echo; echo "FAILED." ;;
|
|
|
|
|
*) printf '%s\n' "$line" ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|