go-scheduler-prompt-board-path
Root cause. The scheduler foreman hard-coded the board path into the spawned agent's prompt as .coding-hermes/tasks.md (root-level, markdown). In JSONL-canonical workspaces that file no longer exists — only .coding-hermes/tasks.md.bak remains — while the canonical board lives at .coding-hermes/board/tasks.jsonl. Every spawned agent was therefore pointed at a stale, nonexistent board.
Fix. Make the foreman board-aware with a boardPath resolver that prefers the JSONL-canonical board and falls back to the tracked-markdown board only for legacy repos. The prompt template literal stays untouched, so the mirror literal in spawn_test.go remains byte-identical.
// scheduler.go
package boardsched
import (
"fmt"
"os"
"path/filepath"
)
// spawnPromptFmt is mirrored byte-for-byte in spawn_test.go — do not alter.
const spawnPromptFmt = "Read the task board at %s and execute the oldest open task.\n"
// boardPath resolves the canonical task board for a workspace.
// Priority: 1) .coding-hermes/board/tasks.jsonl (JSONL-canonical) when present;
// 2) .coding-hermes/tasks.md (tracked-markdown, legacy fallback).
func boardPath(workspace string) string {
jsonl := filepath.Join(workspace, ".coding-hermes", "board", "tasks.jsonl")
if fi, err := os.Stat(jsonl); err == nil && !fi.IsDir() {
return jsonl
}
return filepath.Join(workspace, ".coding-hermes", "tasks.md")
}
func SpawnPrompt(workspace string) string {
return fmt.Sprintf(spawnPromptFmt, boardPath(workspace))
}
The guard lives in the test mirror literal:
// spawn_test.go
const mirrorSpawnPromptFmt = "Read the task board at %s and execute the oldest open task.\n"
func TestSpawnPromptLiteralMirror(t *testing.T) {
if spawnPromptFmt != mirrorSpawnPromptFmt {
t.Fatalf("mirror drift: prod=%q mirror=%q", spawnPromptFmt, mirrorSpawnPromptFmt)
}
}
Verified with `go vet` + `go test -v` (Go 1.26) against a reconstructed workspace: `.coding-hermes/board/tasks.jsonl` (canonical) plus only `.coding-hermes/tasks.md.bak` at root (stale). ``` === RUN TestBoardPathPrefersJSONLCanonical --- PASS === RUN TestBoardPathFallsBackToMarkdown --- PASS === RUN TestSpawnPromptLiteralMirror --- PASS === RUN TestSpawnPromptPointsAtCanonicalBoard --- PASS PASS ok boardsched 0.003s ``` End-to-end foreman run: ``` # canonical workspace (JSONL present, root tasks.md missing): Read the task board at /tmp/boardsched/.coding-hermes/board/tasks.jsonl and execute the oldest open task. (old hard-coded .coding-hermes/tasks.md is missing — would have pointed the agent at a stale path) # legacy workspace (JSONL absent): Read the task board at /tmp/boardsched-legacy/.coding-hermes/tasks.md and execute the oldest open task. ``` **Edge cases tested:** - JSONL board present + root `tasks.md.bak` decoy → resolves to `board/tasks.jsonl` (never the `.bak`). - JSONL board absent → falls back to `.coding-hermes/tasks.md` (tracked-markdown boards keep working). - `boardPath` treats a directory named `tasks.jsonl` as absent (`!fi.IsDir()`), so the fallback still triggers. - Prompt literal byte-identical: production constant, test mirror constant, and the inline golden string all agree — no drift introduced by the fix.
{"model": "deepseek-v4-flash", "problem_class": "go-scheduler-prompt-board-path", "result": "passed", "tests": 4}