There was no existing scheduler repo in this environment, so I implemented the go-fleet-idle-tick-light-audit convention as a self-contained Go module at ~/fleet-scheduler/ (files: scheduler.go, tick.go, lightaudit.go, board.go, appendboardevent.py, plus tests). The fix encodes the convention in four rules:
There was no existing scheduler repo in this environment, so I implemented the go-fleet-idle-tick-light-audit convention as a self-contained Go module at ~/fleet-scheduler/ (files: scheduler.go, tick.go, lightaudit.go, board.go, append_board_event.py, plus tests). The fix encodes the convention in four rules:
1. Fixture-only, not-due ⇒ light path, never a worker — FixtureOnly() is the gate: every pending task must be a fixture (E2E-001/NEVER-DONE) and no fixture's full-battery window may be open. Full-battery windows are first-class (FullBatteryWindow.DueAt, PendingFromWindows).
// scheduler.go
const (
FixtureE2E = "E2E-001"
FixtureNever = "NEVER-DONE"
)
func IsFixture(id string) bool { return id == FixtureE2E || id == FixtureNever }
func FixtureOnly(pending []Pending) bool {
if len(pending) == 0 { return false }
for _, p := range pending {
if !IsFixture(p.ID) || p.FullBatteryDue { return false }
}
return true
}
2. One tick, one decision — Tick() counts ticks_total, resolves last_commit, then branches: fixture-only ⇒ light audit + light verify (no spawn); real work or a due fixture ⇒ spawn worker; empty ⇒ nothing (pause allowed). The board event is appended every tick, including idle and failing ones.
// tick.go
switch {
case FixtureOnly(pending): // idle tick: light audit + light verify, no worker
c.TicksIdle++
res.IdleTick, res.RanLight = true, true
if err := LightAudit(ctx, runner(cfg), nil); err != nil {
firstErr = fmt.Errorf("idle tick light audit: %w", err)
} else if err := LightVerify(ctx, runner(cfg), cfg.Verify); err != nil {
firstErr = fmt.Errorf("idle tick light verify: %w", err)
}
case len(pending) > 0: // real work, or due fixture: dispatch worker
res.SpawnedWorker = true
if cfg.SpawnWorker != nil { firstErr = fmt.Errorf("spawn worker: %w", cfg.SpawnWorker(ctx)) }
}
// Board event always — counters must reflect every tick.
if err := AppendBoardEvent(ctx, runner(cfg), cfg.Script, c); err != nil && firstErr == nil {
firstErr = fmt.Errorf("board event: %w", err)
}
3. Light audit + light verify — the audit roster is build/vet/gofmt/tests/lint/gitreins (gofmt fails on non-empty gofmt -l output; gitreins = git fsck --no-dangling); verify probes daemon health, endpoint battery, and storm-watch (fails when storm_drain_load exceeds the threshold). All steps run through an injectable CommandRunner so tests stub them deterministically.
// lightaudit.go — production roster
{Name: "build", Bin: "go", Args: []string{"build", "./..."}},
{Name: "vet", Bin: "go", Args: []string{"vet", "./..."}},
{Name: "gofmt", Bin: "gofmt", Args: []string{"-l", "."}, Check: ...},
{Name: "tests", Bin: "go", Args: []string{"test", "./..."}},
{Name: "lint", Bin: "golangci-lint", Args: []string{"run", "./..."}},
{Name: "gitreins", Bin: "git", Args: []string{"fsck", "--no-dangling"}},
4. Fixtures gate self-pause, not the idle counter — SelfPauseAllowed consults only the queue: any pending task (fixture included) blocks self-pause; ticks_idle is a pure metric and is never consulted. The board event is appended via append_board_event.py --set ticks_total=N ticks_idle=M last_commit=H (script included; appends a JSONL scheduler_tick event per invocation).
// scheduler.go
func SelfPauseAllowed(pending []Pending) bool { return len(pending) == 0 }
Verified in ~/fleet-scheduler with Go 1.26:
gofmt -l . → clean (no unformatted files)go vet ./... → OKgo test ./... -count=1 -v → 17/17 PASS (ok fleet/scheduler), including a real go build ./... && go vet ./... && gofmt run against this module via the OS runner, and an end-to-end run of append_board_event.py through Python 3.14 (py_compile OK).{"event":"scheduler_tick","last_commit":"abc1234","ticks_idle":9,"ticks_total":12,...}.Edge cases covered by tests:
- Fixture-only, not due → light audit + verify run, 0 workers, ticks_idle++, pause blocked (asserts go/gofmt/golangci-lint/git/curl/python3 all invoked; board args ticks_total=1 ticks_idle=1 last_commit=abc1234).
- Due fixture (window open) → worker spawned, no light path, idle counter unchanged.
- Fixture + real task → worker spawned (fixtures never mask real work).
- Empty queue → no worker, no light, ticks_idle stays 0, self-pause allowed.
- Idle counter vs pause → 499–999 recorded idle ticks with fixtures pending still blocks pause; empty queue with high idle count allows it.
- Duplicate fixtures → still fixture-only; unknown ID (E2E-002) → not a fixture.
- Audit failure (build broken) → error surfaced, no worker, counters still recorded and board event still appended.
- Storm-watch above threshold / malformed report → verify fails; below threshold passes; failed battery probe surfaces.
- last_commit fallback → unknown when git unavailable.
- Note: golangci-lint is not installed here — the lint step is configurable and stubbed in tests; production environments with the binary get it in the default roster (roster membership itself is asserted by TestDefaultAuditRosterIncludesLintAndGitreins).
{"problem_class":"go-fleet-idle-tick-light-audit","model":"deepseek-v4-flash","result":"passed","tests":17}
Solved by Pi Agent (deepseek-v4-flash).
There was no existing scheduler repo in this environment, so I implemented the go-fleet-idle-tick-light-audit convention as a self-contained Go module at ~/fleet-scheduler/ (files: scheduler.go, tick.go, lightaudit.go, board.go, append_board_event.py, plus tests). The fix encodes the convention in four rules:
1. Fixture-only, not-due ⇒ light path, never a worker — FixtureOnly() is the gate: every pending task must be a fixture (E2E-001/NEVER-DONE) and no fixture's full-battery window may be open. Full-battery windows are first-class (FullBatteryWindow.DueAt, PendingFromWindows).
// scheduler.go
const (
FixtureE2E = "E2E-001"
FixtureNever = "NEVER-DONE"
)
func IsFixture(id string) bool { return id == FixtureE2E || id == FixtureNever }
func FixtureOnly(pending []Pending) bool {
if len(pending) == 0 { return false }
for _, p := range pending {
if !IsFixture(p.ID) || p.FullBatteryDue { return false }
}
return true
}
2. One tick, one decision — Tick() counts ticks_total, resolves last_commit, then branches: fixture-only ⇒ light audit + light verify (no spawn); real work or a due fixture ⇒ spawn worker; empty ⇒ nothing (pause allowed). The board event is appended every tick, including idle and failing ones.
// tick.go
switch {
case FixtureOnly(pending): // idle tick: light audit + light verify, no worker
c.TicksIdle++
res.IdleTick, res.RanLight = true, true
if err := LightAudit(ctx, runner(cfg), nil); err != nil {
firstErr = fmt.Errorf("idle tick light audit: %w", err)
} else if err := LightVerify(ctx, runner(cfg), cfg.Verify); err != nil {
firstErr = fmt.Errorf("idle tick light verify: %w", err)
}
case len(pending) > 0: // real work, or due fixture: dispatch worker
res.SpawnedWorker = true
if cfg.SpawnWorker != nil { firstErr = fmt.Errorf("spawn worker: %w", cfg.SpawnWorker(ctx)) }
}
// Board event always — counters must reflect every tick.
if err := AppendBoardEvent(ctx, runner(cfg), cfg.Script, c); err != nil && firstErr == nil {
firstErr = fmt.Errorf("board event: %w", err)
}
3. Light audit + light verify — the audit roster is build/vet/gofmt/tests/lint/gitreins (gofmt fails on non-empty gofmt -l output; gitreins = git fsck --no-dangling); verify probes daemon health, endpoint battery, and storm-watch (fails when storm_drain_load exceeds the threshold). All steps run through an injectable CommandRunner so tests stub them deterministically.
// lightaudit.go — production roster
{Name: "build", Bin: "go", Args: []string{"build", "./..."}},
{Name: "vet", Bin: "go", Args: []string{"vet", "./..."}},
{Name: "gofmt", Bin: "gofmt", Args: []string{"-l", "."}, Check: ...},
{Name: "tests", Bin: "go", Args: []string{"test", "./..."}},
{Name: "lint", Bin: "golangci-lint", Args: []string{"run", "./..."}},
{Name: "gitreins", Bin: "git", Args: []string{"fsck", "--no-dangling"}},
4. Fixtures gate self-pause, not the idle counter — SelfPauseAllowed consults only the queue: any pending task (fixture included) blocks self-pause; ticks_idle is a pure metric and is never consulted. The board event is appended via append_board_event.py --set ticks_total=N ticks_idle=M last_commit=H (script included; appends a JSONL scheduler_tick event per invocation).
// scheduler.go
func SelfPauseAllowed(pending []Pending) bool { return len(pending) == 0 }
Verified in ~/fleet-scheduler with Go 1.26:
gofmt -l . → clean (no unformatted files)go vet ./... → OKgo test ./... -count=1 -v → 17/17 PASS (ok fleet/scheduler), including a real go build ./... && go vet ./... && gofmt run against this module via the OS runner, and an end-to-end run of append_board_event.py through Python 3.14 (py_compile OK).{"event":"scheduler_tick","last_commit":"abc1234","ticks_idle":9,"ticks_total":12,...}.Edge cases covered by tests:
- Fixture-only, not due → light audit + verify run, 0 workers, ticks_idle++, pause blocked (asserts go/gofmt/golangci-lint/git/curl/python3 all invoked; board args ticks_total=1 ticks_idle=1 last_commit=abc1234).
- Due fixture (window open) → worker spawned, no light path, idle counter unchanged.
- Fixture + real task → worker spawned (fixtures never mask real work).
- Empty queue → no worker, no light, ticks_idle stays 0, self-pause allowed.
- Idle counter vs pause → 499–999 recorded idle ticks with fixtures pending still blocks pause; empty queue with high idle count allows it.
- Duplicate fixtures → still fixture-only; unknown ID (E2E-002) → not a fixture.
- Audit failure (build broken) → error surfaced, no worker, counters still recorded and board event still appended.
- Storm-watch above threshold / malformed report → verify fails; below threshold passes; failed battery probe surfaces.
- last_commit fallback → unknown when git unavailable.
- Note: golangci-lint is not installed here — the lint step is configurable and stubbed in tests; production environments with the binary get it in the default roster (roster membership itself is asserted by TestDefaultAuditRosterIncludesLintAndGitreins).
{"problem_class":"go-fleet-idle-tick-light-audit","model":"deepseek-v4-flash","result":"passed","tests":17}
Solved by Pi Agent (deepseek-v4-flash).