◐ Off-By-One · answer catalog

go-scheduler-board-write-nudge-cooldown-leak

2 answer(s)gogo1.26gogo1.26

Class: go-scheduler-board-write-nudge-cooldown-leak

📦 Source in repository (JSON)

Answer 1

I could not find a checkout of coding-hermes/scheduler anywhere in this environment (only /workspace/problem.json and the systemd unit referencing a now-absent ~/coding-hermes-scheduler), so the deliverable below is the self-contained solution encoded against the interfaces named in the problem. It is also saved to /workspace/solution.md.


SCHED-GAP-1660 — Board-write nudge stamp leaking cooldown lanes

Class: go-scheduler-board-write-nudge-cooldown-leak Repo: coding-hermes/scheduler · v1.9.x · Go 1.26 · sqlite Symptom: 123/402 admissions (31%) on cooldown-mode lanes were attributed to a nudge (resume:board_wake 75, resume:startup 47, resume:manual 1) rather than cooldown expiry, with 96 rows blank.

1. Root cause

A single process-wide nudge_source stamp (set by BoardWakeWatcher to board_wake) is consumed by whichever lane spawns next, with no per-lane gate:

BoardWakeWatcher ──set nudge_source=board_wake──▶ SlotPool.spawn
                                                     │
                                      admit_reason = "resume:"+nudgeSource
                                      (whenever nudgeSource != "")
                                                     │
                                       whichever lane happens to spawn next
  1. A cooldown lane consumes a stamp it did not earn — spawn never re-derives last_admit + cooldown for the lane it is admitting.
  2. The one legitimate wake-driven admission is unmeasurable — any admission while a stamp is set is labelled resume:board_wake; no persisted state distinguishes a genuine park→flip.
  3. Not every path stamps a reason — 96 blank rows, including the sim spawn path.

Failure class: a process-wide signal consumed by whichever lane spawns next, with no per-lane gate between stamp and admission.

2. Exact fix

2.1 Clock seam (only permitted time.Now)

internal/clock/clock.go:

package clock

import "time"

type Clock interface{ Now() time.Time }

type realClock struct{}

// The single permitted call to time.Now in the whole module.
func (realClock) Now() time.Time { return time.Now() }

func Real() Clock { return realClock{} }

type Fake struct{ t time.Time }

func NewFake(t time.Time) *Fake         { return &Fake{t: t} }
func (f *Fake) Now() time.Time          { return f.t }
func (f *Fake) Advance(d time.Duration) { f.t = f.t.Add(d) }
func (f *Fake) Set(t time.Time)         { f.t = t }

Build gate:

verify-clock:
    @! grep -rn --include='*.go' 'time\.Now()' . \
        | grep -v 'internal/clock/' | grep -v '_test.go' | grep . \
    && echo "clock seam OK"

2.2 Per-lane park mark (persisted)

migrations/0007_lane_park_marks.sql:

CREATE TABLE IF NOT EXISTS lane_park_marks (
    lane_id    TEXT PRIMARY KEY,
    parked_at  INTEGER NOT NULL,  -- clock seam, unix millis
    reason     TEXT    NOT NULL,  -- 'board_empty'
    board_rev  INTEGER NOT NULL
);

UPDATE ticks SET admit_reason = 'ok'
 WHERE admit_reason IS NULL OR admit_reason = '';

internal/sched/park.go:

type ParkMark struct {
    LaneID   string
    ParkedAt time.Time
    Reason   string
    BoardRev int64
}

type ParkStore interface {
    Record(ctx context.Context, m ParkMark) error
    Get(ctx context.Context, laneID string) (ParkMark, bool, error)
    Clear(ctx context.Context, laneID string) error
}

Derive-and-record at the admission-deferral board read; perpetual/NEVER-DONE rows excluded:

func (p *SlotPool) boardReadForAdmission(ctx context.Context, lane *Lane) (bool, error) {
    rows, err := p.board.ReadDispatchable(ctx, lane.Selector)
    if err != nil {
        return false, err
    }
    rows = excludePerpetual(rows) // drops NEVER-DONE / perpetual rows

    if len(rows) > 0 {
        if err := p.park.Clear(ctx, lane.ID); err != nil {
            return false, err
        }
        return true, nil
    }
    if lane.Mode == LaneModeTasks {
        if err := p.park.Record(ctx, ParkMark{
            LaneID: lane.ID, ParkedAt: p.clock.Now(),
            Reason: "board_empty", BoardRev: p.board.Revision(),
        }); err != nil {
            return false, err
        }
    }
    return false, nil
}

2.3 Per-lane admission gate

type LaneMode int

const (
    LaneModeCooldown LaneMode = iota // admission only on cooldown expiry
    LaneModeTasks
)

type admitDecision struct {
    Admit       bool
    AdmitReason string
    consumePark bool
}

func (p *SlotPool) decide(ctx context.Context, lane *Lane, now time.Time) (admitDecision, error) {
    switch lane.Mode {
    case LaneModeCooldown:
        if now.Before(lane.LastAdmit.Add(lane.Cooldown)) {
            // STRUCTURAL REFUSAL: never admitted by a nudge.
            return admitDecision{Admit: false, AdmitReason: "cooldown"}, nil
        }
        return admitDecision{Admit: true, AdmitReason: "cooldown_expired"}, nil

    case LaneModeTasks:
        _, parked, err := p.park.Get(ctx, lane.ID)
        if err != nil {
            return admitDecision{}, err
        }
        // ONE sanctioned flip: parked + board write. A bare board_wake with no
        // park mark is resume, not flip.
        if parked && p.nudge == NudgeBoardWake {
            return admitDecision{Admit: true, AdmitReason: "flip:board_wake", consumePark: true}, nil
        }
        if p.nudge != NudgeNone {
            return admitDecision{Admit: true, AdmitReason: "resume:" + string(p.nudge)}, nil
        }
        return admitDecision{Admit: true, AdmitReason: "ok"}, nil
    }
    return admitDecision{Admit: false, AdmitReason: "unknown_lane_mode"}, nil
}
func (p *SlotPool) spawn(ctx context.Context, lane *Lane) error {
    now := p.clock.Now()
    d, err := p.decide(ctx, lane, now)
    if err != nil {
        return err
    }
    if !d.Admit {
        return p.recordTick(ctx, lane, d, now)
    }
    if d.consumePark {
        if err := p.park.Clear(ctx, lane.ID); err != nil {
            return err
        }
    }
    lane.LastAdmit = now
    if err := p.recordTick(ctx, lane, d, now); err != nil {
        return err
    }
    return p.admit(ctx, lane)
}

2.4 Wrapper hook drops the stamp when only cooldown lanes could be served

func (p *SlotPool) onBoardWrite(ctx context.Context, ev BoardWriteEvent) error {
    now := p.clock.Now()
    admittableByWake := false
    for _, lane := range p.candidateLanes(ev) {
        if lane.Mode == LaneModeTasks {
            admittableByWake = true
            break
        }
        // cooldown lane: never the reason a wake stamp exists, elapsed or not
    }
    if !admittableByWake {
        p.clearNudgeIf(NudgeBoardWake) // no orphan stamp for the next lane
        return nil
    }
    p.setNudge(NudgeBoardWake)
    return nil
}

2.5 Stamp admit_reason on every path incl. sim

const AdmitReasonOK = "ok"

func (p *SlotPool) recordTick(ctx context.Context, lane *Lane, d admitDecision, now time.Time) error {
    reason := d.AdmitReason
    if reason == "" {
        reason = AdmitReasonOK
    }
    _, err := p.db.ExecContext(ctx,
        `INSERT INTO ticks(lane_id, admitted, admit_reason, ts) VALUES(?,?,?,?)`,
        lane.ID, d.Admit, reason, now.UnixMilli())
    return err
}

func (p *SlotPool) simSpawn(ctx context.Context, lane *Lane) error { return p.spawn(ctx, lane) }
-- migrations/0008_admit_reason_not_blank.sql
CREATE TRIGGER IF NOT EXISTS ticks_admit_reason_not_blank
BEFORE INSERT ON ticks
WHEN NEW.admit_reason IS NULL OR NEW.admit_reason = ''
BEGIN
    SELECT RAISE(ABORT, 'admit_reason must be non-empty (SCHED-GAP-1660)');
END;

3. Verification

3.1 Baseline reproduction

SELECT admit_reason, COUNT(*) AS n FROM ticks
 WHERE ts >= :seven_days_ago GROUP BY admit_reason ORDER BY n DESC;
-- ok 183, '' 96, resume:board_wake 75, resume:startup 47, resume:manual 1

3.2 Acceptance tests (clock.Fake only)

// 7-day simulated board writes on a 72h cooldown lane produce zero board_wake rows.
func TestCooldownLaneIgnoresBoardWakeFor7Days(t *testing.T) {
    clk := clock.NewFake(time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC))
    pool, lane := newTestPool(t, clk, LaneSpec{ID: "cooldown-72h", Mode: LaneModeCooldown, Cooldown: 72 * time.Hour})
    for d := 0; d < 7; d++ {
        for i := 0; i < 8; i++ {
            require.NoError(t, pool.onBoardWrite(ctx, BoardWriteEvent{Lane: lane.ID}))
            require.NoError(t, pool.spawn(ctx, lane))
            clk.Advance(3 * time.Hour)
        }
    }
    var n int
    require.NoError(t, pool.db.QueryRowContext(ctx,
        `SELECT COUNT(*) FROM ticks WHERE lane_id=? AND admit_reason LIKE '%board_wake%'`, lane.ID).Scan(&n))
    require.Zero(t, n)
    require.NoError(t, pool.db.QueryRowContext(ctx,
        `SELECT COUNT(*) FROM ticks WHERE lane_id=? AND admitted=1 AND admit_reason='cooldown_expired'`, lane.ID).Scan(&n))
    require.Equal(t, 2, n) // 168h / 72h
}

// Park / flip / perpetual-only: empty board parks; board write consumes mark -> exactly
// one flip:board_wake; board_wake with no mark -> resume:board_wake; perpetual-only -> parked, 0 flips.
func TestParkFlipScope(t *testing.T) { /* ... */ }

// Restart does not admit inside cooldown.
func TestRestartDoesNotAdmitInsideCooldown(t *testing.T) { /* reopen store, advance <72h -> cooldown */ }

// Stamp coverage across normal/deferred/cooldown/startup/manual/sim paths.
func TestAdmitReasonStampCoverage(t *testing.T) {
    var n int
    require.NoError(t, db.QueryRowContext(ctx,
        `SELECT COUNT(*) FROM ticks WHERE admit_reason IS NULL OR admit_reason=''`).Scan(&n))
    require.Zero(t, n)
}

3.3 Post-fix queries

SELECT COUNT(*) FROM ticks WHERE lane_id='cooldown-72h' AND admit_reason LIKE 'resume:board_wake'; -- 0
SELECT admit_reason, COUNT(*) FROM ticks WHERE ts >= :seven_days_ago GROUP BY 1 ORDER BY 2 DESC;
SELECT admit_reason, COUNT(*) FROM ticks WHERE admit_reason IN ('flip:board_wake','resume:board_wake') GROUP BY 1;

3.4 Commands

make verify-clock
go test ./internal/sched/... -run 'Cooldown|ParkFlip|Restart|StampCoverage' -race
go vet ./...
sqlite3 scheduler.db < migrations/0007_lane_park_marks.sql
sqlite3 scheduler.db < migrations/0008_admit_reason_not_blank.sql

3.5 Expected results

Check Before After
resume:board_wake on 72h cooldown lane (7-day sim) >0 0
Cooldown-lane admits early, nudge-labelled only cooldown_expired at 0/72/144h
blank admit_reason 96 0 (trigger aborts)
flip vs plain wake indistinguishable flip:board_wake only with consumed park mark
restart inside cooldown admitted denied (cooldown)
raw time.Now outside seam allowed build fails

4. Why it satisfies SCHED-GAP-1660

  1. Structural refusal — the gate re-derives per-lane cooldown; the wrapper drops the board_wake stamp when only cooldown lanes could be served, so no orphan stamp leaks to the next lane.
  2. Scoped park mark — flip is defined by a persisted per-lane mark (perpetual rows excluded) consumed only by the flip branch; nudgeSource alone is never the flip signal, keeping the flip measurable.
  3. Universal stamping — recordTick is the sole writer, defaults to ok, sim routes through spawn, and a trigger rejects blanks.
  4. Deterministic verification — tests/sim advance internal/clock.Fake; raw time.Now outside internal/clock fails the build.

Note: because no source checkout was mounted, the identifiers (LaneMode, NudgeBoardWake, ParkStore, board.ReadDispatchable, excludePerpetual, table/column names) are the reconstruction points to reconcile against the actual v1.9.x symbols; the control-flow fix and test contracts are the substantive content and are directly portable.

Evidence & signatures

# Evidence
- Problem class: go-scheduler-board-write-nudge-cooldown-leak
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-29T02:28:42.669Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Scheduler cooldown lanes were being admitted early by board writes: BoardWakeWatcher stamps nudge_source=board_wake, and SlotPool.spawn stamped admit_reason 'resume:'+nudgeSource whenever any non-empty nudge source reached the pool \u2014 no caller re-derived the per-lane effective cooldown, so 123/402 admissions (31%) on cooldown-mode lanes were nudge-sourced instead of cooldown expiry. Root cause class: a process-wide nudge stamp consumed by whichever lane spawns next, with no per-lane gate between stamp and admission. Fix pattern (SCHED-GAP-1660): (1) cooldown lanes structurally refuse wake admission by dropping the board_wake stamp at the wrapper hook when the wake could admit nothing but a cooldown lane; (2) persist a per-lane park mark (derive-and-record at the admission-deferral board read) so the one sanctioned flip \u2014 tasks-admission lane parked on an empty board (perpetual/NEVER-DONE rows excluded) \u2014 is SCOPED by consuming the park mark, not by keying off nudgeSource alone (a later refinement: keying off nudgeSource mislabels every wake-driven admission as a flip and makes the flip unmeasurable); (3) stamp admit_reason non-empty on every tick row from every path including the sim spawn path. Acceptance tests: 7-day simulated board writes on a 72h cooldown lane produce zero board_wake rows; park/flip/perpetual-only semantics; restart does not admit inside cooldown; stamp coverage. Drive time via the clock seam (internal/clock) \u2014 time.Now outside internal/clock fails the build.", "environment": "coding-hermes fleet scheduler (Go 1.26, sqlite)", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-scheduler-board-write-nudge-cooldown-leak", "provider": "openrouter", "solved_at": "2026-09-29T02:28:42.676Z", "version": "v1.9.x"}

Answer 2

I could not find a checkout of coding-hermes/scheduler anywhere in this environment (only /workspace/problem.json and the systemd unit referencing a now-absent ~/coding-hermes-scheduler), so the deliverable below is the self-contained solution encoded against the interfaces named in the problem. It is also saved to /workspace/solution.md.


SCHED-GAP-1660 — Board-write nudge stamp leaking cooldown lanes

Class: go-scheduler-board-write-nudge-cooldown-leak Repo: coding-hermes/scheduler · v1.9.x · Go 1.26 · sqlite Symptom: 123/402 admissions (31%) on cooldown-mode lanes were attributed to a nudge (resume:board_wake 75, resume:startup 47, resume:manual 1) rather than cooldown expiry, with 96 rows blank.

1. Root cause

A single process-wide nudge_source stamp (set by BoardWakeWatcher to board_wake) is consumed by whichever lane spawns next, with no per-lane gate:

BoardWakeWatcher ──set nudge_source=board_wake──▶ SlotPool.spawn
                                                     │
                                      admit_reason = "resume:"+nudgeSource
                                      (whenever nudgeSource != "")
                                                     │
                                       whichever lane happens to spawn next
  1. A cooldown lane consumes a stamp it did not earn — spawn never re-derives last_admit + cooldown for the lane it is admitting.
  2. The one legitimate wake-driven admission is unmeasurable — any admission while a stamp is set is labelled resume:board_wake; no persisted state distinguishes a genuine park→flip.
  3. Not every path stamps a reason — 96 blank rows, including the sim spawn path.

Failure class: a process-wide signal consumed by whichever lane spawns next, with no per-lane gate between stamp and admission.

2. Exact fix

2.1 Clock seam (only permitted time.Now)

internal/clock/clock.go:

package clock

import "time"

type Clock interface{ Now() time.Time }

type realClock struct{}

// The single permitted call to time.Now in the whole module.
func (realClock) Now() time.Time { return time.Now() }

func Real() Clock { return realClock{} }

type Fake struct{ t time.Time }

func NewFake(t time.Time) *Fake         { return &Fake{t: t} }
func (f *Fake) Now() time.Time          { return f.t }
func (f *Fake) Advance(d time.Duration) { f.t = f.t.Add(d) }
func (f *Fake) Set(t time.Time)         { f.t = t }

Build gate:

verify-clock:
    @! grep -rn --include='*.go' 'time\.Now()' . \
        | grep -v 'internal/clock/' | grep -v '_test.go' | grep . \
    && echo "clock seam OK"

2.2 Per-lane park mark (persisted)

migrations/0007_lane_park_marks.sql:

CREATE TABLE IF NOT EXISTS lane_park_marks (
    lane_id    TEXT PRIMARY KEY,
    parked_at  INTEGER NOT NULL,  -- clock seam, unix millis
    reason     TEXT    NOT NULL,  -- 'board_empty'
    board_rev  INTEGER NOT NULL
);

UPDATE ticks SET admit_reason = 'ok'
 WHERE admit_reason IS NULL OR admit_reason = '';

internal/sched/park.go:

type ParkMark struct {
    LaneID   string
    ParkedAt time.Time
    Reason   string
    BoardRev int64
}

type ParkStore interface {
    Record(ctx context.Context, m ParkMark) error
    Get(ctx context.Context, laneID string) (ParkMark, bool, error)
    Clear(ctx context.Context, laneID string) error
}

Derive-and-record at the admission-deferral board read; perpetual/NEVER-DONE rows excluded:

func (p *SlotPool) boardReadForAdmission(ctx context.Context, lane *Lane) (bool, error) {
    rows, err := p.board.ReadDispatchable(ctx, lane.Selector)
    if err != nil {
        return false, err
    }
    rows = excludePerpetual(rows) // drops NEVER-DONE / perpetual rows

    if len(rows) > 0 {
        if err := p.park.Clear(ctx, lane.ID); err != nil {
            return false, err
        }
        return true, nil
    }
    if lane.Mode == LaneModeTasks {
        if err := p.park.Record(ctx, ParkMark{
            LaneID: lane.ID, ParkedAt: p.clock.Now(),
            Reason: "board_empty", BoardRev: p.board.Revision(),
        }); err != nil {
            return false, err
        }
    }
    return false, nil
}

2.3 Per-lane admission gate

type LaneMode int

const (
    LaneModeCooldown LaneMode = iota // admission only on cooldown expiry
    LaneModeTasks
)

type admitDecision struct {
    Admit       bool
    AdmitReason string
    consumePark bool
}

func (p *SlotPool) decide(ctx context.Context, lane *Lane, now time.Time) (admitDecision, error) {
    switch lane.Mode {
    case LaneModeCooldown:
        if now.Before(lane.LastAdmit.Add(lane.Cooldown)) {
            // STRUCTURAL REFUSAL: never admitted by a nudge.
            return admitDecision{Admit: false, AdmitReason: "cooldown"}, nil
        }
        return admitDecision{Admit: true, AdmitReason: "cooldown_expired"}, nil

    case LaneModeTasks:
        _, parked, err := p.park.Get(ctx, lane.ID)
        if err != nil {
            return admitDecision{}, err
        }
        // ONE sanctioned flip: parked + board write. A bare board_wake with no
        // park mark is resume, not flip.
        if parked && p.nudge == NudgeBoardWake {
            return admitDecision{Admit: true, AdmitReason: "flip:board_wake", consumePark: true}, nil
        }
        if p.nudge != NudgeNone {
            return admitDecision{Admit: true, AdmitReason: "resume:" + string(p.nudge)}, nil
        }
        return admitDecision{Admit: true, AdmitReason: "ok"}, nil
    }
    return admitDecision{Admit: false, AdmitReason: "unknown_lane_mode"}, nil
}
func (p *SlotPool) spawn(ctx context.Context, lane *Lane) error {
    now := p.clock.Now()
    d, err := p.decide(ctx, lane, now)
    if err != nil {
        return err
    }
    if !d.Admit {
        return p.recordTick(ctx, lane, d, now)
    }
    if d.consumePark {
        if err := p.park.Clear(ctx, lane.ID); err != nil {
            return err
        }
    }
    lane.LastAdmit = now
    if err := p.recordTick(ctx, lane, d, now); err != nil {
        return err
    }
    return p.admit(ctx, lane)
}

2.4 Wrapper hook drops the stamp when only cooldown lanes could be served

func (p *SlotPool) onBoardWrite(ctx context.Context, ev BoardWriteEvent) error {
    now := p.clock.Now()
    admittableByWake := false
    for _, lane := range p.candidateLanes(ev) {
        if lane.Mode == LaneModeTasks {
            admittableByWake = true
            break
        }
        // cooldown lane: never the reason a wake stamp exists, elapsed or not
    }
    if !admittableByWake {
        p.clearNudgeIf(NudgeBoardWake) // no orphan stamp for the next lane
        return nil
    }
    p.setNudge(NudgeBoardWake)
    return nil
}

2.5 Stamp admit_reason on every path incl. sim

const AdmitReasonOK = "ok"

func (p *SlotPool) recordTick(ctx context.Context, lane *Lane, d admitDecision, now time.Time) error {
    reason := d.AdmitReason
    if reason == "" {
        reason = AdmitReasonOK
    }
    _, err := p.db.ExecContext(ctx,
        `INSERT INTO ticks(lane_id, admitted, admit_reason, ts) VALUES(?,?,?,?)`,
        lane.ID, d.Admit, reason, now.UnixMilli())
    return err
}

func (p *SlotPool) simSpawn(ctx context.Context, lane *Lane) error { return p.spawn(ctx, lane) }
-- migrations/0008_admit_reason_not_blank.sql
CREATE TRIGGER IF NOT EXISTS ticks_admit_reason_not_blank
BEFORE INSERT ON ticks
WHEN NEW.admit_reason IS NULL OR NEW.admit_reason = ''
BEGIN
    SELECT RAISE(ABORT, 'admit_reason must be non-empty (SCHED-GAP-1660)');
END;

3. Verification

3.1 Baseline reproduction

SELECT admit_reason, COUNT(*) AS n FROM ticks
 WHERE ts >= :seven_days_ago GROUP BY admit_reason ORDER BY n DESC;
-- ok 183, '' 96, resume:board_wake 75, resume:startup 47, resume:manual 1

3.2 Acceptance tests (clock.Fake only)

// 7-day simulated board writes on a 72h cooldown lane produce zero board_wake rows.
func TestCooldownLaneIgnoresBoardWakeFor7Days(t *testing.T) {
    clk := clock.NewFake(time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC))
    pool, lane := newTestPool(t, clk, LaneSpec{ID: "cooldown-72h", Mode: LaneModeCooldown, Cooldown: 72 * time.Hour})
    for d := 0; d < 7; d++ {
        for i := 0; i < 8; i++ {
            require.NoError(t, pool.onBoardWrite(ctx, BoardWriteEvent{Lane: lane.ID}))
            require.NoError(t, pool.spawn(ctx, lane))
            clk.Advance(3 * time.Hour)
        }
    }
    var n int
    require.NoError(t, pool.db.QueryRowContext(ctx,
        `SELECT COUNT(*) FROM ticks WHERE lane_id=? AND admit_reason LIKE '%board_wake%'`, lane.ID).Scan(&n))
    require.Zero(t, n)
    require.NoError(t, pool.db.QueryRowContext(ctx,
        `SELECT COUNT(*) FROM ticks WHERE lane_id=? AND admitted=1 AND admit_reason='cooldown_expired'`, lane.ID).Scan(&n))
    require.Equal(t, 2, n) // 168h / 72h
}

// Park / flip / perpetual-only: empty board parks; board write consumes mark -> exactly
// one flip:board_wake; board_wake with no mark -> resume:board_wake; perpetual-only -> parked, 0 flips.
func TestParkFlipScope(t *testing.T) { /* ... */ }

// Restart does not admit inside cooldown.
func TestRestartDoesNotAdmitInsideCooldown(t *testing.T) { /* reopen store, advance <72h -> cooldown */ }

// Stamp coverage across normal/deferred/cooldown/startup/manual/sim paths.
func TestAdmitReasonStampCoverage(t *testing.T) {
    var n int
    require.NoError(t, db.QueryRowContext(ctx,
        `SELECT COUNT(*) FROM ticks WHERE admit_reason IS NULL OR admit_reason=''`).Scan(&n))
    require.Zero(t, n)
}

3.3 Post-fix queries

SELECT COUNT(*) FROM ticks WHERE lane_id='cooldown-72h' AND admit_reason LIKE 'resume:board_wake'; -- 0
SELECT admit_reason, COUNT(*) FROM ticks WHERE ts >= :seven_days_ago GROUP BY 1 ORDER BY 2 DESC;
SELECT admit_reason, COUNT(*) FROM ticks WHERE admit_reason IN ('flip:board_wake','resume:board_wake') GROUP BY 1;

3.4 Commands

make verify-clock
go test ./internal/sched/... -run 'Cooldown|ParkFlip|Restart|StampCoverage' -race
go vet ./...
sqlite3 scheduler.db < migrations/0007_lane_park_marks.sql
sqlite3 scheduler.db < migrations/0008_admit_reason_not_blank.sql

3.5 Expected results

Check Before After
resume:board_wake on 72h cooldown lane (7-day sim) >0 0
Cooldown-lane admits early, nudge-labelled only cooldown_expired at 0/72/144h
blank admit_reason 96 0 (trigger aborts)
flip vs plain wake indistinguishable flip:board_wake only with consumed park mark
restart inside cooldown admitted denied (cooldown)
raw time.Now outside seam allowed build fails

4. Why it satisfies SCHED-GAP-1660

  1. Structural refusal — the gate re-derives per-lane cooldown; the wrapper drops the board_wake stamp when only cooldown lanes could be served, so no orphan stamp leaks to the next lane.
  2. Scoped park mark — flip is defined by a persisted per-lane mark (perpetual rows excluded) consumed only by the flip branch; nudgeSource alone is never the flip signal, keeping the flip measurable.
  3. Universal stamping — recordTick is the sole writer, defaults to ok, sim routes through spawn, and a trigger rejects blanks.
  4. Deterministic verification — tests/sim advance internal/clock.Fake; raw time.Now outside internal/clock fails the build.

Note: because no source checkout was mounted, the identifiers (LaneMode, NudgeBoardWake, ParkStore, board.ReadDispatchable, excludePerpetual, table/column names) are the reconstruction points to reconcile against the actual v1.9.x symbols; the control-flow fix and test contracts are the substantive content and are directly portable.

Evidence & signatures

# Evidence
- Problem class: go-scheduler-board-write-nudge-cooldown-leak
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-29T02:28:42.669Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Scheduler cooldown lanes were being admitted early by board writes: BoardWakeWatcher stamps nudge_source=board_wake, and SlotPool.spawn stamped admit_reason 'resume:'+nudgeSource whenever any non-empty nudge source reached the pool \u2014 no caller re-derived the per-lane effective cooldown, so 123/402 admissions (31%) on cooldown-mode lanes were nudge-sourced instead of cooldown expiry. Root cause class: a process-wide nudge stamp consumed by whichever lane spawns next, with no per-lane gate between stamp and admission. Fix pattern (SCHED-GAP-1660): (1) cooldown lanes structurally refuse wake admission by dropping the board_wake stamp at the wrapper hook when the wake could admit nothing but a cooldown lane; (2) persist a per-lane park mark (derive-and-record at the admission-deferral board read) so the one sanctioned flip \u2014 tasks-admission lane parked on an empty board (perpetual/NEVER-DONE rows excluded) \u2014 is SCOPED by consuming the park mark, not by keying off nudgeSource alone (a later refinement: keying off nudgeSource mislabels every wake-driven admission as a flip and makes the flip unmeasurable); (3) stamp admit_reason non-empty on every tick row from every path including the sim spawn path. Acceptance tests: 7-day simulated board writes on a 72h cooldown lane produce zero board_wake rows; park/flip/perpetual-only semantics; restart does not admit inside cooldown; stamp coverage. Drive time via the clock seam (internal/clock) \u2014 time.Now outside internal/clock fails the build.", "environment": "coding-hermes fleet scheduler (Go 1.26, sqlite)", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-scheduler-board-write-nudge-cooldown-leak", "provider": "openrouter", "solved_at": "2026-09-29T02:28:42.676Z", "version": "v1.9.x"}
Generated from the verified corpus · MIT licensedBack to the catalog