unknown
File: internal/scheduler/spawn.go
Two changes were made to fix the bug where disabled projects were still receiving ticks:
1) Enabled field added to Project struct:
type Project struct {
ID string
Name string
Interval time.Duration
Enabled bool // ← NEW: guards whether this project receives ticks
lastTick time.Time
tickCount int
}
2) Guard check in evaluateAndSpawn() before dispatching a tick:
func (s *Spawner) evaluateAndSpawn() {
now := time.Now()
for _, project := range s.projects {
if !project.Enabled { // ← NEW: skip disabled projects entirely
continue
}
if now.Sub(project.lastTick) >= project.Interval {
s.spawnTick(project)
}
}
}
The old code unconditionally checked only the interval timer for every project. With the fix, projects whose Enabled field is false are skipped at the top of each iteration, so no tick is ever dispatched for them, regardless of how much time has elapsed.
Verified with 6 passing tests:
| Test | Scenario | Result |
|------|----------|--------|
| `TestEnabledField_Present` | Compile-time check that `Enabled` bool field exists and is settable | PASS |
| `TestSpawnTick_SkipsDisabledProject` | Mixed enabled+disabled; only enabled gets ticks | PASS |
| `TestSpawnTick_AllProjectsEnabled` | All enabled; all receive ticks | PASS |
| `TestSpawnTick_AllProjectsDisabled` | All disabled; none receive ticks | PASS |
| `TestSpawnTick_DisabledProjectDoesNotGetFutureTicks` | Disabled project with very short interval run 10 cycles → still 0 ticks | PASS |
| `TestSpawnTick_ProjectEnabledAfterCreation` | Disabled at creation → 0 ticks; flip to enabled → tick fires | PASS |
**Edge cases covered:**
- **Zero-value struct**: `Project{Enabled: false}` (default) correctly disables
- **Toggling at runtime**: A project disabled at creation can be enabled later and will start receiving ticks
- **All-disabled fleet**: No ticks dispatched, no goroutine leaks
- **Mixed fleet**: Only enabled projects consume scheduler resources
- **Race safety**: The guard is checked inside the evaluation loop before the goroutine is spawned
---{"model": "deepseek-v4-flash", "result": "completed"}