chore: land the remaining low-severity items from the whole-project review
Phase 11 of PROJECT_REVIEW_PLAN.md: the themed cleanup pass over every low-severity finding still open (2.2-2.3, 3.4-3.6, 4.3-4.7, 6.4-6.7, 7.1-7.3, 8.2-8.3, 9.1-9.4, and the under-documented decisions in §10/§11). Behavioral fixes: - Reassign duplicate job IDs in a hand-edited jobs.json instead of letting two jobs share one runtime, schedule entry, and SeedStats bucket. - Disambiguate run-log file names that collide within the same second. - Compute AvgDurationMS as DurationSumMS/TimedRunCount instead of an incremental integer mean, so it always matches the seeded-from-logs average instead of drifting from truncation error. - Clean absolute paths in ResolveConfiguredPath so two spellings of the same jobs file do not trigger a spurious adoption. - Report InstallDesktopIcon failures through ErrorOccurred instead of discarding them silently. - Move settingsView's blocking AutostartStatus (PowerShell on Windows) off the UI thread. - Give notify-timing.tsv its own extension so CleanupLogs no longer manages it as a run log. - Replace the settingsView Save handler's second copy of validateConfig's rules with a bare parse, letting the Service's own error surface. Cleanups: - Delete collectActivity, the dead yaml tags on RunRecord, and the logArguments/LogArguments alias. - Fold the two systemTrayRegistered/mainWindowHidden globals into one trayState instance Run owns and threads through Settings and the single-instance reveal path. - Fix stale comments/docs: the frozen window-size restore claim, a reference to a renamed recordRun, README's "Pause all" and notification wording, the PowerShell quoting note for TESTS.md's coverage command, and scripts/test.bat's UTF-8 checkmarks under a non-UTF-8 code page. - Document the single-instance fallback's consequence and the unauthenticated instance-channel port in STANDARDS.md; record the config-shim retirement plan in ROADMAP.md. 3.5, 7.3, and 9.4 turned out to already be fixed by earlier phases; no change needed for those three. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+12
-5
@@ -1,18 +1,25 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitea.mixdep.ru/mix/gosentry/src/platform/desktop"
|
||||
)
|
||||
|
||||
// InstallDesktopIcon installs the application's .desktop file and icon on
|
||||
// Linux (no-op on other platforms). The resulting icon path is stored in
|
||||
// store.Paths.DesktopIcon so ApplyAutostart can reference it.
|
||||
// store.Paths.DesktopIcon so ApplyAutostart can reference it. A failure is
|
||||
// reported through ErrorOccurred rather than discarded, so the visible symptom
|
||||
// (a generic dock icon) has an explanation in History instead of none.
|
||||
func (s *Service) InstallDesktopIcon(appID string, iconBytes []byte) {
|
||||
if iconPath, err := desktop.InstallDesktopIntegration(appID, s.store.Paths.ExecutablePath, iconBytes); err == nil {
|
||||
s.mu.Lock()
|
||||
s.store.Paths.DesktopIcon = iconPath
|
||||
s.mu.Unlock()
|
||||
iconPath, err := desktop.InstallDesktopIntegration(appID, s.store.Paths.ExecutablePath, iconBytes)
|
||||
if err != nil {
|
||||
s.emit(ErrorOccurred{Err: fmt.Errorf("install desktop icon: %w", err)})
|
||||
return
|
||||
}
|
||||
s.mu.Lock()
|
||||
s.store.Paths.DesktopIcon = iconPath
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
// AutostartStatus reports whether the platform autostart entry matches the
|
||||
|
||||
+2
-1
@@ -253,7 +253,8 @@ func updateStats(rt *domain.JobRuntime, r domain.RunRecord) {
|
||||
rt.MaxDurationMS = r.DurationMS
|
||||
}
|
||||
rt.TimedRunCount++
|
||||
rt.AvgDurationMS = (rt.AvgDurationMS*int64(rt.TimedRunCount-1) + r.DurationMS) / int64(rt.TimedRunCount)
|
||||
rt.DurationSumMS += r.DurationMS
|
||||
rt.AvgDurationMS = rt.DurationSumMS / int64(rt.TimedRunCount)
|
||||
}
|
||||
|
||||
// runningOutput is the placeholder output shown while a job is running, before
|
||||
|
||||
@@ -103,6 +103,15 @@ func TestUpdateStats(t *testing.T) {
|
||||
if rt.AvgDurationMS != 233 {
|
||||
t.Errorf("after run 3: avg=%d, want 233", rt.AvgDurationMS)
|
||||
}
|
||||
// AvgDurationMS must always be exactly DurationSumMS/TimedRunCount — a stored
|
||||
// sum divided once, not an incremental mean that truncates on every step and
|
||||
// compounds error over a long-running job.
|
||||
if rt.DurationSumMS != 700 {
|
||||
t.Errorf("DurationSumMS = %d, want 700", rt.DurationSumMS)
|
||||
}
|
||||
if want := rt.DurationSumMS / int64(rt.TimedRunCount); rt.AvgDurationMS != want {
|
||||
t.Errorf("AvgDurationMS = %d, want DurationSumMS/TimedRunCount = %d", rt.AvgDurationMS, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateStatsSkipsZeroDuration(t *testing.T) {
|
||||
|
||||
@@ -151,6 +151,7 @@ func (s *Service) applySeededStatsLocked(seeds map[int]runner.SeededStats) {
|
||||
runtime.AvgDurationMS = seed.AvgDurationMS
|
||||
runtime.MaxDurationMS = seed.MaxDurationMS
|
||||
runtime.TimedRunCount = seed.TimedRunCount
|
||||
runtime.DurationSumMS = seed.DurationSumMS
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user