Extract the gesture vocabulary from the code that implements it
Every gesture the application has was documented in the comment beside the `TouchArea` that implements it. Excellent comments, and unreachable by anyone not reading the source — which is the FR-UI-4 failure in a different costume: a gesture nobody can find is a feature only its author knows about. Writing them out again in a hand-kept help page is the failure this avoids. Two descriptions of one gesture drift, and it is always the prose that drifts: the code is exercised every time somebody uses the application and the page is exercised never. A help screen confidently describing a double tap the grid stopped honouring last week is worse than no help screen — and the grid did stop honouring one, in the commit before this. So the comment beside the implementation stays the only copy, and a `GESTURE:` block beside it is scanned into two artefacts: `docs/gestures.md` for a reader, and a Rust table for the application to draw a help sheet from. Both committed, both gated, so neither can quietly stop describing the code. It lives in the traceability crate because it is the same operation on the same input — walk the tree, pull structured tags out of comments, render, fail if the committed artefact has moved. Only the vocabulary is new. It scans `ui` and `apps` alone: a gesture needs an interface to be performed on, and excluding `tools` is also what stops the scanner extracting its own worked examples as broken gestures. Fifteen gestures so far, across the library grid and the People screen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -127,6 +127,14 @@ component FaceCell inherits Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// GESTURE: Pull a face out of the wrong person
|
||||
// where: People
|
||||
// touch: Tap the faces that do not belong, then "Split off"
|
||||
// pointer: Click the faces that do not belong, then "Split off"
|
||||
// why: Grouping over-merges on siblings, on parents and
|
||||
// children, and on the same person a decade apart, so
|
||||
// splitting is as prominent as merging. A tool that can
|
||||
// only merge makes its own errors permanent.
|
||||
TouchArea {
|
||||
clicked => { root.toggle-pick(); }
|
||||
}
|
||||
@@ -139,6 +147,14 @@ component FaceCell inherits Rectangle {
|
||||
// Only a suggestion needs ruling on. Once confirmed, the pair
|
||||
// collapses to the label — there is nothing left to decide, and
|
||||
// leaving the buttons would invite an accidental un-confirm.
|
||||
// GESTURE: Rule on a suggested face
|
||||
// where: People
|
||||
// touch: Tick to confirm it, cross to reject it
|
||||
// pointer: Tick to confirm it, cross to reject it
|
||||
// why: A face is either the system's guess or the user's
|
||||
// judgement, and the two are never conflated. A
|
||||
// rejection is remembered, so the face is not suggested
|
||||
// for that person again.
|
||||
if !face.confirmed: IconButton {
|
||||
icon: "check";
|
||||
clicked => { root.confirm(); }
|
||||
@@ -526,6 +542,13 @@ export component IdentityScreen inherits Rectangle {
|
||||
// The way back from a face to the photographs. This is the
|
||||
// point of having identified anybody, and without it the
|
||||
// screen is a filing cabinet with no drawer handles.
|
||||
// GESTURE: See a person's photographs
|
||||
// where: People
|
||||
// touch: Choose them in the rail, then "Show photos"
|
||||
// pointer: Choose them in the rail, then "Show photos"
|
||||
// why: This is the point of having identified anybody.
|
||||
// Without it the screen is a filing cabinet with no
|
||||
// drawer handles.
|
||||
if root.selected-person >= 0: Button {
|
||||
text: "Show photos";
|
||||
clicked => { root.show-photos(root.selected-person, false); }
|
||||
@@ -556,6 +579,15 @@ export component IdentityScreen inherits Rectangle {
|
||||
// next to the button that applies them and the rail that shows
|
||||
// what they did, and a value changed three screens away from
|
||||
// its effect is a value nobody can tune.
|
||||
// GESTURE: Change how faces are grouped
|
||||
// where: People
|
||||
// touch: "Grouping…", move the dials, then Regroup
|
||||
// pointer: "Grouping…", move the dials, then Regroup
|
||||
// why: The right match confidence is a property of your
|
||||
// library, not of the model. "What would this do?"
|
||||
// answers for this library without writing
|
||||
// anything; names, confirmations and the groups you
|
||||
// have set aside are kept whatever the dials say.
|
||||
Button {
|
||||
text: "Grouping…";
|
||||
active: root.grouping-open;
|
||||
|
||||
Reference in New Issue
Block a user