Summary
ScanAttention and ScanAttentionQuick in internal/data/attention.go (lines 87–163) share an identical preamble: resolve state directory, read directory entries, allocate result map, iterate entries with the same IsDir and SessionID validation guards. The only difference is the classification logic inside the loop body.
Anti-pattern
Copy-paste — two functions with ~20 lines of duplicated scaffolding that diverge only in classification strategy.
| Function |
Lines |
Classification |
| ScanAttention |
87–115 |
Calls classifySession for every entry |
| ScanAttentionQuick |
121–163 |
Checks PID first, skips events.jsonl for dead sessions |
Suggested fix
Extract the shared directory-scanning loop into a helper that accepts a classification callback:
go func scanSessions(classify func(dir string) AttentionStatus) map[string]AttentionStatus { stateDir := sessionStatePath() if stateDir == "" { return nil } entries, err := os.ReadDir(stateDir) if err != nil { return nil } result := make(map[string]AttentionStatus, len(entries)) for _, e := range entries { if !e.IsDir() { continue } sessionID := e.Name() if !validate.SessionID(sessionID) { continue } result[sessionID] = classify(filepath.Join(stateDir, sessionID)) } return result }
Then ScanAttention and ScanAttentionQuick become thin wrappers passing their respective classification functions.
Audit grade: C
Summary
ScanAttention and ScanAttentionQuick in internal/data/attention.go (lines 87–163) share an identical preamble: resolve state directory, read directory entries, allocate result map, iterate entries with the same IsDir and SessionID validation guards. The only difference is the classification logic inside the loop body.
Anti-pattern
Copy-paste — two functions with ~20 lines of duplicated scaffolding that diverge only in classification strategy.
Suggested fix
Extract the shared directory-scanning loop into a helper that accepts a classification callback:
go func scanSessions(classify func(dir string) AttentionStatus) map[string]AttentionStatus { stateDir := sessionStatePath() if stateDir == "" { return nil } entries, err := os.ReadDir(stateDir) if err != nil { return nil } result := make(map[string]AttentionStatus, len(entries)) for _, e := range entries { if !e.IsDir() { continue } sessionID := e.Name() if !validate.SessionID(sessionID) { continue } result[sessionID] = classify(filepath.Join(stateDir, sessionID)) } return result }Then ScanAttention and ScanAttentionQuick become thin wrappers passing their respective classification functions.
Audit grade: C