chore: snapshot production code before Apple Design UI refinement

This commit is contained in:
lingniu
2026-09-17 18:05:57 +08:00
parent 9f0a87f49e
commit f7e7176f88
90 changed files with 8990 additions and 328 deletions
@@ -924,9 +924,7 @@ func (w *Writer) applyRealtimeBaseline(ctx context.Context, candidate *SourceMil
return nil
}
if !IsUsableDailyMileageBoundary(candidate.StatDate, baseline.LatestEventTime, w.loc) {
// A vehicle recovering after one or more empty natural days must start a
// fresh day boundary. Otherwise the complete offline-period odometer
// increase is incorrectly assigned to the recovery day.
// A future/invalid boundary cannot be used for this natural day.
candidate.FirstTotalKM = candidate.LatestTotalKM
candidate.FirstEventTime = candidate.LatestEventTime
candidate.DailyKM = 0
@@ -1453,7 +1453,7 @@ func TestWriterAppendUsesPreviousSourceBaselineForRealtimeCandidate(t *testing.T
}
}
func TestWriterAppendStartsCurrentDayBoundaryAfterOfflineGap(t *testing.T) {
func TestWriterAppendUsesHistoricalBoundaryAfterOfflineGap(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("sqlmock.New() error = %v", err)
@@ -1494,18 +1494,18 @@ func TestWriterAppendStartsCurrentDayBoundaryAfterOfflineGap(t *testing.T) {
"",
"LMRKH9AC2R1004087",
"",
float64(120672.0),
float64(120788.0),
float64(120788.0),
float64(0),
float64(116),
float64(0),
int64(1),
int64(0),
currentTime,
historicalTime,
currentTime,
false,
false,
QualityOK,
QualityReasonCurrentDayFirst,
QualityReasonHistorical,
).
WillReturnResult(sqlmock.NewResult(0, 1))
mock.ExpectExec(`INSERT INTO vehicle_daily_mileage`).
@@ -1711,7 +1711,7 @@ func TestWriterApplyRealtimeBaselineRejectsNegativeDeltaEvenWithLowerCurrentDayS
}
}
func TestWriterApplyRealtimeBaselineIgnoresPlausibleMultiDayFallbackDelta(t *testing.T) {
func TestWriterApplyRealtimeBaselineIncludesPlausibleMultiDayFallbackDelta(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("sqlmock.New() error = %v", err)
@@ -1740,14 +1740,14 @@ func TestWriterApplyRealtimeBaselineIgnoresPlausibleMultiDayFallbackDelta(t *tes
if err := writer.applyRealtimeBaseline(context.Background(), &candidate); err != nil {
t.Fatalf("applyRealtimeBaseline() error = %v", err)
}
if candidate.QualityStatus != QualityOK || candidate.QualityReason != QualityReasonCurrentDayFirst {
if candidate.QualityStatus != QualityOK || candidate.QualityReason != QualityReasonHistorical {
t.Fatalf("quality = %s/%s", candidate.QualityStatus, candidate.QualityReason)
}
if candidate.DailyKM != 0 {
t.Fatalf("daily km = %v, want current-day first baseline after offline gap", candidate.DailyKM)
if math.Abs(candidate.DailyKM-7833.5) > 0.000001 {
t.Fatalf("daily km = %v, want historical cumulative difference after offline gap", candidate.DailyKM)
}
if candidate.FirstTotalKM != candidate.LatestTotalKM || !candidate.FirstEventTime.Equal(currentTime) {
t.Fatalf("current-day boundary not retained: %#v", candidate)
if candidate.FirstTotalKM != 8832.1 || !candidate.FirstEventTime.Equal(baselineTime) {
t.Fatalf("historical boundary not retained: %#v", candidate)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("sql expectations: %v", err)
@@ -1798,7 +1798,7 @@ func TestWriterApplyRealtimeBaselineRejectsProtocolOdometerRollbackAfterSourceCh
}
}
func TestWriterApplyRealtimeBaselineIgnoresHistoricalBaselineJumpAcrossOfflineGap(t *testing.T) {
func TestWriterApplyRealtimeBaselineRejectsHistoricalBaselineJumpAcrossOfflineGap(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("sqlmock.New() error = %v", err)
@@ -1827,14 +1827,14 @@ func TestWriterApplyRealtimeBaselineIgnoresHistoricalBaselineJumpAcrossOfflineGa
if err := writer.applyRealtimeBaseline(context.Background(), &candidate); err != nil {
t.Fatalf("applyRealtimeBaseline() error = %v", err)
}
if candidate.QualityStatus != QualityOK || candidate.QualityReason != QualityReasonCurrentDayFirst {
if candidate.QualityStatus != QualityInvalidDelta || candidate.QualityReason != "outside_daily_range" {
t.Fatalf("quality = %s/%s", candidate.QualityStatus, candidate.QualityReason)
}
if candidate.DailyKM != 0 {
t.Fatalf("daily km = %v, want current-day first baseline", candidate.DailyKM)
if math.Abs(candidate.DailyKM-30000) > 0.000001 {
t.Fatalf("daily km = %v, want historical cumulative difference", candidate.DailyKM)
}
if candidate.FirstTotalKM != candidate.LatestTotalKM || !candidate.FirstEventTime.Equal(currentTime) {
t.Fatalf("current-day boundary not retained: %#v", candidate)
if candidate.FirstTotalKM != 10009.7 || !candidate.FirstEventTime.Equal(baselineTime) {
t.Fatalf("historical boundary not retained: %#v", candidate)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("sql expectations: %v", err)
@@ -137,10 +137,8 @@ func DailyMileageFromDayBoundary(previousBaselineKM float64, currentDayLatestKM
return currentDayLatestKM - previousBaselineKM
}
// IsUsableDailyMileageBoundary reports whether a persisted baseline belongs to
// the current natural day or its immediately preceding natural day. A baseline
// from an older day represents an offline gap; using it would attribute the
// whole gap to the day on which the vehicle came back online.
// IsUsableDailyMileageBoundary accepts older same-source odometers.
// Offline increments belong to the recovery day so cumulative totals reconcile.
func IsUsableDailyMileageBoundary(statDate string, baselineTime time.Time, loc *time.Location) bool {
if strings.TrimSpace(statDate) == "" || baselineTime.IsZero() {
return false
@@ -154,7 +152,7 @@ func IsUsableDailyMileageBoundary(statDate string, baselineTime time.Time, loc *
}
baseline := baselineTime.In(loc)
baselineDay := time.Date(baseline.Year(), baseline.Month(), baseline.Day(), 0, 0, 0, 0, loc)
return !baselineDay.Before(day.AddDate(0, 0, -1)) && !baselineDay.After(day)
return !baselineDay.After(day)
}
func NormalizeDailyMileageDeltaForWindow(deltaKM float64, firstEventTime time.Time, latestEventTime time.Time) (float64, bool, string) {
@@ -754,7 +752,9 @@ const selectedSourceIdentitySampleCountSQL = `(
// from the daily-mileage projection. GPS coordinate accumulation can be the
// best evidence for distance travelled during the day, but it must never
// replace a terminal-reported odometer as the day-end cumulative mileage.
const projectDayEndTotalMileageSQL = `COALESCE((
const projectDayEndTotalMileageSQL = `CASE
WHEN COALESCE(s.quality_reason, '') <> '` + QualityReasonGPSCoordinate + `' THEN s.latest_total_mileage_km
ELSE COALESCE((
SELECT total_candidate.latest_total_mileage_km
FROM vehicle_daily_mileage_source total_candidate
WHERE total_candidate.vin = s.vin
@@ -771,7 +771,7 @@ const projectDayEndTotalMileageSQL = `COALESCE((
total_candidate.sample_count DESC,
total_candidate.source_key ASC
LIMIT 1
), s.latest_total_mileage_km)`
), s.latest_total_mileage_km) END`
const projectDailyMileageSQL = `
INSERT INTO vehicle_daily_mileage
@@ -279,7 +279,7 @@ func TestDailyMileageFromDayBoundaryUsesCurrentMinusPrevious(t *testing.T) {
}
}
func TestIsUsableDailyMileageBoundaryRejectsOlderOfflineGap(t *testing.T) {
func TestIsUsableDailyMileageBoundaryAcceptsOlderOfflineGap(t *testing.T) {
loc := time.FixedZone("Asia/Shanghai", 8*3600)
for _, test := range []struct {
name string
@@ -288,7 +288,7 @@ func TestIsUsableDailyMileageBoundaryRejectsOlderOfflineGap(t *testing.T) {
}{
{name: "current day cache", baseline: time.Date(2026, 8, 4, 19, 1, 26, 0, loc), want: true},
{name: "previous natural day", baseline: time.Date(2026, 8, 3, 23, 59, 59, 0, loc), want: true},
{name: "older offline gap", baseline: time.Date(2026, 5, 21, 23, 13, 2, 0, loc), want: false},
{name: "older offline gap", baseline: time.Date(2026, 5, 21, 23, 13, 2, 0, loc), want: true},
{name: "future boundary", baseline: time.Date(2026, 8, 5, 0, 0, 0, 0, loc), want: false},
} {
t.Run(test.name, func(t *testing.T) {