Replace per-kind reclassify with a single global reclassify that respects manual and Race locks

Manual assignments are the user's definitive word and Race assignments come
from a hard Garmin fact (eventType.typeKey), not a retunable rule -- neither
is ever touched by reclassify again, and Race can no longer be set by hand
via the review queue. Adds an Activities page so this locked/unlocked status
is visible per workout, since Review Queue only ever showed unresolved items.
This commit is contained in:
2026-07-19 11:11:50 +02:00
parent 8ff3d62b2f
commit 0610897541
15 changed files with 398 additions and 60 deletions

View File

@@ -83,6 +83,27 @@ func (db *DB) ReviewQueue(ctx context.Context) ([]KindAssignment, error) {
return assignments, rows.Err()
}
// AllCurrentAssignments returns the latest assignment for every activity
// that has one, regardless of status or source -- the basis for deciding
// which activities a global reclassify pass is allowed to touch.
func (db *DB) AllCurrentAssignments(ctx context.Context) ([]KindAssignment, error) {
rows, err := db.QueryContext(ctx, `SELECT `+kindAssignmentColumns+` FROM current_kind_assignment`)
if err != nil {
return nil, fmt.Errorf("all current assignments: %w", err)
}
defer rows.Close()
assignments := []KindAssignment{}
for rows.Next() {
a, err := scanKindAssignment(rows)
if err != nil {
return nil, fmt.Errorf("scan kind assignment row: %w", err)
}
assignments = append(assignments, a)
}
return assignments, rows.Err()
}
// AssignmentsForKind returns every historical assignment where the given
// workout kind was the resolved kind (regardless of source), oldest first --
// the basis for progression-over-time charts.