Commit graph fingerprintd/packaging/fplearn.sh
Author SHA1 Message Date
9d026b5d48 fplearn.sh: enrol with learning off, so a fresh template starts clean
Enrolment does not use learning, but the enrol step left the daemon running with
it enabled, so the brand-new template started folding the moment anything
verified. That is precisely the contamination a fresh-template control is meant
to exclude, and the control is the next thing being run. trend turns it back on.
2026-09-05 02:06:24 +02:00
30bb987c27 A template restore destroys the template; refuse it, and stop caching a failed load
The paired test I built cannot exist on this hardware, and finding that out cost
Jorijn his enrolled finger.

Restoring an earlier container byte for byte made the trustlet read its header,
UNLINK it, look for a .bak and advance the RPMB counter -- for both containers.
QTEE binds every SFS object to a hardware anti-rollback counter, so an earlier
version is not stale to it, it is tampered, and the response to tampering is
deletion. No copy can undo that. The journal has warned about this counter since
August in the context of the group index; it applies to the template itself just
as hard, and I did not check before building a feature on the assumption that it
did not.

So restore refuses and explains, with the measurement in the message. Snapshots
stay: they are still forensic evidence of what a template looked like, they just
cannot be put back. Changing a template means enrolling again.

The daemon compounded it. The group-selection cache stored "0 templates loaded"
as a valid answer, so once the trustlet had unlinked everything, every later
claim answered "skipped (already active, 0 template(s))" and never tried again.
It now caches only a positive result, so a failed load is retried rather than
made permanent.
2026-09-05 01:44:15 +02:00
756093e847 Fold one frame per press, not eight -- and put snapshots where the user can find them
Four matches, each followed by a template save, then five consecutive failures.
Jorijn asked whether it was user error. It was not.

Over one evening the harvest folded 185 frames into a template whose
max_sub_template_num is 96, and the template went from matching ten presses out
of ten to failing five in a row. The frames one press contributes are
near-duplicates of a single image, so folding eight of them per press does not
add coverage: it spends the template's slots on one finger position and evicts
the diversity the enrolment put there. Stock's roughly forty-six updates in a
session are spread across many separate presses, which is where diversity
actually comes from.

So one fold per matched press, which also needs no extra capture at all because
the matching frame is already inside the trustlet. Eight remains available for a
deliberate experiment.

The snapshot directory was resolved from $HOME while the script is run under
sudo, so every snapshot landed in /root/fp6-backups and looked, from the user's
shell, like it had never been taken. That is the one thing that would have made
this unrecoverable, and it was caught only because the restore was needed. It
now resolves the invoking user's home.
2026-09-05 01:36:10 +02:00
f3da01a511 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.
2026-09-04 23:49:25 +02:00
edb0d8e530 Spend the presses on the open question, and report what learning actually folded
Two changes to the measurement, both about not wasting a finger.

The wrong-finger control is off by default now. Across every run this project
has made the wrong finger has matched zero times out of forty-odd taps; the
question that is still open is the false-negative rate, and each control tap
spends a press that could have measured it. Pass a count to put the control
back, and the summary says plainly when it was not run rather than printing a
zero that reads like a result.

And a trend run now reports how many frames learning folded, out of the daemon's
own transcript, alongside the container size. Without that a run cannot tell
"learning fired and did not help" from "learning never fired" -- which is exactly
the confusion that let the first trend run measure a static template three times
and look like a result.

Default trial length goes to fifteen taps, since dropping the control freed the
presses and ten was too few to separate three-in-ten from five-in-ten.
2026-09-04 23:43:47 +02:00
f5c7b6d3b5 fplearn.sh: a wipe step, and enrol refuses a finger the group already holds
Measured 2026-09-04: the trustlet's duplicated-finger check refuses to re-enrol
a finger it already has a template for -- 0 accepted of 7 presses, rc=0 on each,
while a never-enrolled finger progressed normally. Re-enrolment adds a template
and there is no trustlet-side remove, so a measured finger's old template has to
go before it can be enrolled again.

wipe does that the way it has been done by hand twice: backup first, daemon
stopped so the trustlet reloads from the store, only the template containers
removed, the group index kept because deleting it risks the RPMB anti-rollback
counters going stale, the name map cleared, then a restart and the sizes.

enrol checks the name map and refuses a finger that is already there, pointing
at wipe, so the refusal cannot be mistaken for bad pressing again.
2026-09-04 23:06:45 +02:00
c5fc3afc77 Add fplearn.sh, because a cumulative measurement is a protocol not three commands
Learning rewrites the template on every matched press, so run two is not a
repeat of run one and an A/B against a moving template is not an A/B. The order
is the measurement:

  enrol   a fresh template at 20 samples with no position prompts, which is also
          the outstanding replication of the best result this lane has seen
  base    learning off: the clean number for that template, and the only figure
          comparable to every rate already recorded
  trend   learning on, three times: the rate should climb, with the container
          size as an independent witness that it is the template moving

A rate that climbs while the body grows is learning. A rate that moves while the
body does not is noise, and the daemon's own learn: lines say which. Run one of
the trend is not evidence that learning helped; it starts on the template the
baseline ended on.

One limit the script states rather than letting someone discover it: learning
only fires on a press that matched, so a template that never matches never
improves. That is why the protocol re-enrols instead of building on a template
already measured at 0 of 10.
2026-09-03 17:46:33 +02:00