🔍 Duplicate Code Detected: Near-identical fuzzy-cron scatter handlers
Analysis of commit 3fd44f8
Assignee: @copilot
Summary
pkg/parser/schedule_fuzzy_scatter.go contains a family of handle* functions that are structurally near-identical. The weekday vs. non-weekday variants (and the around/between pairs) differ only in a prefix constant, the cron day-of-week field (* * * vs * * 1-5), and the log label. This is a textbook copy-paste cluster: 3+ highly similar pattern pairs.
Duplication Details
Pattern: fuzzy-cron handler bodies differing by constants
- Severity: Medium
- Occurrences: 3+ near-identical pairs across 14
handle* functions
- Locations (representative pairs):
handleDailyAroundWeekdays (227-240) ⇄ handleDailyAround (257-270) — differ by prefix + 1-5 day field
handleDailyBetweenWeekdays (242-255) ⇄ handleDailyBetween (272-285)
handleHourlyWeekdays (307-320) ⇄ handleHourly (322-335)
- Code Sample:
func handleDailyAroundWeekdays(fuzzyCron, workflowIdentifier string) (string, bool, error) {
const prefix = "FUZZY:DAILY_AROUND_WEEKDAYS:"
if !strings.HasPrefix(fuzzyCron, prefix) { return "", false, nil }
targetHour, targetMinute, err := parseAroundTarget(fuzzyCron, prefix, /* 4 error strings */)
if err != nil { return "", true, err }
hour, minute := scatterAroundTime(targetHour, targetMinute, workflowIdentifier)
result := fmt.Sprintf("%d %d * * 1-5", minute, hour) // <- only diff: "1-5" vs "*"
scheduleFuzzyScatterLog.Printf("FUZZY:DAILY_AROUND_WEEKDAYS scattered: ...", ...)
return result, true, nil
}
handleDailyAround is the same code with prefix FUZZY:DAILY_AROUND:, day field *, and a different log label.
Impact Analysis
- Maintainability: 14 handlers repeat the same prefix-check / parse / scatter / format skeleton. Behavioral changes (e.g. error wrapping, logging format) must be repeated many times.
- Bug Risk: Divergence between weekday/non-weekday variants is easy to introduce and hard to spot (e.g. forgetting the
1-5 day field).
- Code Bloat: Dozens of redundant lines across the handler family.
Refactoring Recommendations
-
Extract a parameterized around/between helper
- Introduce helpers like
handleAround(fuzzyCron, id, prefix, dayField, logLabel) and handleBetween(...), then make each public handler a thin one-line delegation supplying the prefix, dayField ("*" or "1-5"), and label.
- Estimated effort: ~1-2 hrs, medium complexity.
- Benefits: removes the weekday/non-weekday divergence risk; one place to evolve error strings and logging.
-
Optionally drive dispatch from a table
- Replace the handler list with a slice of
{prefix, kind, dayField, label} descriptors iterated by the dispatcher, eliminating most hand-written handlers.
Implementation Checklist
Analysis Metadata
- Analyzed Files: pkg/ (1435 non-test .go files)
- Detection Method: Serena semantic code analysis + normalized structural fingerprinting
- Commit: 3fd44f8
- Analysis Date: 2026-10-06
Generated by 🔍 Duplicate Code Detector · pi · opus48 · 74.5 AIC · ⌖ 41.3 AIC · ⊞ 1.5K · ◷
🔍 Duplicate Code Detected: Near-identical fuzzy-cron scatter handlers
Analysis of commit 3fd44f8
Assignee:
@copilotSummary
pkg/parser/schedule_fuzzy_scatter.gocontains a family ofhandle*functions that are structurally near-identical. The weekday vs. non-weekday variants (and the around/between pairs) differ only in a prefix constant, the cron day-of-week field (* * *vs* * 1-5), and the log label. This is a textbook copy-paste cluster: 3+ highly similar pattern pairs.Duplication Details
Pattern: fuzzy-cron handler bodies differing by constants
handle*functionshandleDailyAroundWeekdays(227-240) ⇄handleDailyAround(257-270) — differ by prefix +1-5day fieldhandleDailyBetweenWeekdays(242-255) ⇄handleDailyBetween(272-285)handleHourlyWeekdays(307-320) ⇄handleHourly(322-335)handleDailyAroundis the same code with prefixFUZZY:DAILY_AROUND:, day field*, and a different log label.Impact Analysis
1-5day field).Refactoring Recommendations
Extract a parameterized
around/betweenhelperhandleAround(fuzzyCron, id, prefix, dayField, logLabel)andhandleBetween(...), then make each public handler a thin one-line delegation supplying the prefix,dayField("*"or"1-5"), and label.Optionally drive dispatch from a table
{prefix, kind, dayField, label}descriptors iterated by the dispatcher, eliminating most hand-written handlers.Implementation Checklist
around/betweenhelpers parameterized by prefix/day-field/labelhandle*to a thin delegation (or table entry)make fmtandmake test-unitAnalysis Metadata