Problem class: go-sqlite-append-only-telemetry-context
Solution written to ~/SOLUTION.md. The fixes were compiled and verified against a runnable Go 1.25 + modernc.org/sqlite reproduction (all 8 tests pass, go vet clean).
Problem class: go-sqlite-append-only-telemetry-context
The unit tests and the Tier 1 guard were green because they asserted that a row was written, not that history was preserved. Adversarial acceptance found four semantic contract violations.
INSERT OR REPLACE rewrites historysrc/telemetry/telemetry.go persisted rows with:
INSERT OR REPLACE INTO telemetry (...) VALUES (...)
SQLite implements INSERT OR REPLACE as DELETE the conflicting row, then INSERT a new one. Any second write for the same natural key destroys started_at, the original status, env snapshot and error, changes the row identity (not append-only), and makes the 3-run canary retain fewer rows when keys collide. First-write-wins must be ON CONFLICT ... DO NOTHING.
src/runner/telemetry.go (and runner.go / tsrun.go) used os.Getenv/os.Environ only. Scheduler-provided runner-scoped metadata (HERMES_RUN_ID, deadlines, trace ids) never reached the node process or the telemetry env snapshot. The lookup must merge runner env over process env, runner winning.
src/runner/tsrun.go / runner.go reported node totals as the number of dispatch-loop iterations and persisted them as iteration_count. Unknown measurements must stay 0 until a real metric exists.
Parse/prepare errors returned before the telemetry write, so the node silently vanished. Every terminal path, including pre-execution failures, must write exactly one terminal row.
Schema — immutable identity, no UPDATE path:
CREATE TABLE IF NOT EXISTS telemetry (
run_id TEXT NOT NULL,
node_id TEXT NOT NULL,
attempt INTEGER NOT NULL DEFAULT 0,
phase TEXT NOT NULL,
status TEXT NOT NULL,
started_at TEXT NOT NULL,
ended_at TEXT,
iteration_count INTEGER NOT NULL DEFAULT 0, -- 0 == unknown, never invented
env TEXT NOT NULL DEFAULT '{}', -- merged process+runner snapshot
error TEXT NOT NULL DEFAULT '',
PRIMARY KEY (run_id, node_id, attempt, phase)
);
Record — first-write-wins:
func (l *Ledger) Record(ctx context.Context, e Event) (bool, error) {
env, err := json.Marshal(e.Env)
if err != nil { return false, fmt.Errorf("encode env: %w", err) }
var ended any
if e.EndedAt != nil { ended = e.EndedAt.UTC().Format(time.RFC3339Nano) }
res, err := l.db.ExecContext(ctx, `
INSERT INTO telemetry
(run_id, node_id, attempt, phase, status, started_at, ended_at,
iteration_count, env, error)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (run_id, node_id, attempt, phase) DO NOTHING`,
e.RunID, e.NodeID, e.Attempt, e.Phase, e.Status,
e.StartedAt.UTC().Format(time.RFC3339Nano), ended,
e.IterationCount, string(env), e.Error)
if err != nil { return false, fmt.Errorf("telemetry insert: %w", err) }
n, err := res.RowsAffected()
if err != nil { return false, err }
return n == 1, nil // false == duplicate ignored; history untouched
}
Merge runner env over process env:
func MergeEnv(process []string, runner map[string]string) []string {
merged := make(map[string]string, len(process)+len(runner))
for _, kv := range process {
k, v, ok := strings.Cut(kv, "=")
if !ok || k == "" { continue }
merged[k] = v
}
for k, v := range runner {
if k == "" { continue }
merged[k] = v // runner/scheduler scope overrides process scope
}
out := make([]string, 0, len(merged))
for k, v := range merged { out = append(out, k+"="+v) }
sort.Strings(out)
return out
}
func LookupEnv(process []string, runner map[string]string, key string) (string, bool) {
if v, ok := runner[key]; ok { return v, true } // runner wins
for _, kv := range process {
if k, v, ok := strings.Cut(kv, "="); ok && k == key { return v, true }
}
return "", false
}
Unknown totals stay zero:
type NodeMetrics struct {
Iterations int // zero value == not measured
Bytes int64
DurationMS int64
}
func nodeTotals(m *NodeMetrics) int {
if m == nil { return 0 }
return m.Iterations // never derived from loop/attempt indices
}
Pre-execution failures become terminal rows:
func RunNode(ctx context.Context, ledger *telemetry.Ledger, runID string,
n Node, attempt int, processEnv []string,
metrics *NodeMetrics, now func() time.Time) (RunResult, error) {
res := RunResult{Status: "failed"}
env := MergeEnv(processEnv, n.Env)
prepared, err := prepare(n) // parse/prepare BEFORE execution
if err != nil {
res.Err = err.Error()
if rerr := recordTerminal(ctx, ledger, runID, n, attempt, env, res, metrics, now); rerr != nil {
return res, rerr
}
return res, err // terminal row already written
}
res, err = execute(ctx, prepared)
if err != nil { res.Err = err.Error() }
if rerr := recordTerminal(ctx, ledger, runID, n, attempt, env, res, metrics, now); rerr != nil {
return res, rerr
}
return res, err
}
func recordTerminal(ctx context.Context, ledger *telemetry.Ledger, runID string,
n Node, attempt int, env []string, res RunResult,
metrics *NodeMetrics, now func() time.Time) error {
start := now().UTC()
end := start
_, err := ledger.Record(ctx, telemetry.Event{
RunID: runID, NodeID: n.ID, Attempt: attempt, Phase: "terminal",
Status: res.Status, StartedAt: start, EndedAt: &end,
IterationCount: nodeTotals(metrics), // 0 when unknown
Env: envMap(env), Error: res.Err,
})
return err
}
$ go build ./... && go vet ./...
$ go test ./... -count=1 -v
=== RUN TestMergeEnvRunnerOverridesProcess --- PASS
=== RUN TestLookupEnvUsesRunnerScope --- PASS
=== RUN TestParseFailureRecordsTerminalRow --- PASS
=== RUN TestUnknownIterationsStayZero --- PASS
=== RUN TestRealIterationsPersisted --- PASS
=== RUN TestThreeRunCanaryRetainsThreeRows --- PASS
=== RUN TestFirstWriteWinsOnConflictDoNothing --- PASS
=== RUN TestInsertOrReplaceWouldMutateHistory --- PASS
PASS
ok vtest/runner 0.005s
ok vtest/telemetry 0.005s
| Contract | Check | Result |
|---|---|---|
| Append-only | Duplicate Record returns inserted=false; Get equals first write |
PASS |
| No history rewrite | INSERT OR REPLACE mutates; production path uses DO NOTHING |
PASS |
| Runner context | Runner env overrides HERMES_RUN_ID; runner-only key resolvable |
PASS |
| Honest metrics | nil metrics -> iteration_count=0; real metrics persisted |
PASS |
| Failure coverage | prepare failure yields terminal/failed row |
PASS |
| Canary durability | 3 runs -> 3 rows, retained after close/re-open | PASS |
Run against the real repo:
$ go test ./... -count=1
$ golangci-lint run ./... # expect 0 issues
$ for i in 1 2 3; do <project> run --telemetry /tmp/canary.db --run-id "canary-$i" canary-node; done
$ sqlite3 /tmp/canary.db 'SELECT COUNT(*) FROM telemetry;'
3
$ rm -f /tmp/canary.checkpoint
$ sqlite3 /tmp/canary.db 'SELECT COUNT(*) FROM telemetry;'
3
| File | Change |
|---|---|
src/telemetry/telemetry.go |
Schema primary key on immutable identity; Record uses ON CONFLICT (...) DO NOTHING; no UPDATE/OR REPLACE path. |
src/telemetry/telemetry_test.go |
First-write-wins test + OR REPLACE mutation contrast test. |
src/runner/telemetry.go |
MergeEnv/LookupEnv merge runner env over process env. |
src/runner/runner.go |
All terminal paths (incl. pre-execution parse/prepare failures) write one terminal row; records merged env. |
src/runner/tsrun.go |
nodeTotals returns real metrics, 0 when unknown; never loop indices. |
src/runner/telemetry_test.go |
Env precedence, terminal-on-parse-failure, unknown/real totals, 3-run canary. |
# Evidence - Problem class: go-sqlite-append-only-telemetry-context - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-11T19:11:39.710Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "A scheduler-run telemetry ledger implementation can look complete while violating its core contract: INSERT OR REPLACE mutates supposedly append-only history, process-only environment lookup drops runner-scoped scheduler metadata, and node totals are incorrectly invented as iteration counts. Use first-write-wins ON CONFLICT DO NOTHING, merge runner Env over process Env, keep unknown iteration counts at zero until real metrics exist, and cover pre-execution parse/prepare failures as terminal rows.", "environment": "Linux; Go; SQLite telemetry ledger integrated with a DAG runner and scheduler-provided context", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-sqlite-append-only-telemetry-context", "provider": "openrouter", "solved_at": "2026-09-11T19:11:39.710Z", "version": "1.25.0"}Solution written to ~/SOLUTION.md. The fixes were compiled and verified against a runnable Go 1.25 + modernc.org/sqlite reproduction (all 8 tests pass, go vet clean).
Problem class: go-sqlite-append-only-telemetry-context
The unit tests and the Tier 1 guard were green because they asserted that a row was written, not that history was preserved. Adversarial acceptance found four semantic contract violations.
INSERT OR REPLACE rewrites historysrc/telemetry/telemetry.go persisted rows with:
INSERT OR REPLACE INTO telemetry (...) VALUES (...)
SQLite implements INSERT OR REPLACE as DELETE the conflicting row, then INSERT a new one. Any second write for the same natural key destroys started_at, the original status, env snapshot and error, changes the row identity (not append-only), and makes the 3-run canary retain fewer rows when keys collide. First-write-wins must be ON CONFLICT ... DO NOTHING.
src/runner/telemetry.go (and runner.go / tsrun.go) used os.Getenv/os.Environ only. Scheduler-provided runner-scoped metadata (HERMES_RUN_ID, deadlines, trace ids) never reached the node process or the telemetry env snapshot. The lookup must merge runner env over process env, runner winning.
src/runner/tsrun.go / runner.go reported node totals as the number of dispatch-loop iterations and persisted them as iteration_count. Unknown measurements must stay 0 until a real metric exists.
Parse/prepare errors returned before the telemetry write, so the node silently vanished. Every terminal path, including pre-execution failures, must write exactly one terminal row.
Schema — immutable identity, no UPDATE path:
CREATE TABLE IF NOT EXISTS telemetry (
run_id TEXT NOT NULL,
node_id TEXT NOT NULL,
attempt INTEGER NOT NULL DEFAULT 0,
phase TEXT NOT NULL,
status TEXT NOT NULL,
started_at TEXT NOT NULL,
ended_at TEXT,
iteration_count INTEGER NOT NULL DEFAULT 0, -- 0 == unknown, never invented
env TEXT NOT NULL DEFAULT '{}', -- merged process+runner snapshot
error TEXT NOT NULL DEFAULT '',
PRIMARY KEY (run_id, node_id, attempt, phase)
);
Record — first-write-wins:
func (l *Ledger) Record(ctx context.Context, e Event) (bool, error) {
env, err := json.Marshal(e.Env)
if err != nil { return false, fmt.Errorf("encode env: %w", err) }
var ended any
if e.EndedAt != nil { ended = e.EndedAt.UTC().Format(time.RFC3339Nano) }
res, err := l.db.ExecContext(ctx, `
INSERT INTO telemetry
(run_id, node_id, attempt, phase, status, started_at, ended_at,
iteration_count, env, error)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (run_id, node_id, attempt, phase) DO NOTHING`,
e.RunID, e.NodeID, e.Attempt, e.Phase, e.Status,
e.StartedAt.UTC().Format(time.RFC3339Nano), ended,
e.IterationCount, string(env), e.Error)
if err != nil { return false, fmt.Errorf("telemetry insert: %w", err) }
n, err := res.RowsAffected()
if err != nil { return false, err }
return n == 1, nil // false == duplicate ignored; history untouched
}
Merge runner env over process env:
func MergeEnv(process []string, runner map[string]string) []string {
merged := make(map[string]string, len(process)+len(runner))
for _, kv := range process {
k, v, ok := strings.Cut(kv, "=")
if !ok || k == "" { continue }
merged[k] = v
}
for k, v := range runner {
if k == "" { continue }
merged[k] = v // runner/scheduler scope overrides process scope
}
out := make([]string, 0, len(merged))
for k, v := range merged { out = append(out, k+"="+v) }
sort.Strings(out)
return out
}
func LookupEnv(process []string, runner map[string]string, key string) (string, bool) {
if v, ok := runner[key]; ok { return v, true } // runner wins
for _, kv := range process {
if k, v, ok := strings.Cut(kv, "="); ok && k == key { return v, true }
}
return "", false
}
Unknown totals stay zero:
type NodeMetrics struct {
Iterations int // zero value == not measured
Bytes int64
DurationMS int64
}
func nodeTotals(m *NodeMetrics) int {
if m == nil { return 0 }
return m.Iterations // never derived from loop/attempt indices
}
Pre-execution failures become terminal rows:
func RunNode(ctx context.Context, ledger *telemetry.Ledger, runID string,
n Node, attempt int, processEnv []string,
metrics *NodeMetrics, now func() time.Time) (RunResult, error) {
res := RunResult{Status: "failed"}
env := MergeEnv(processEnv, n.Env)
prepared, err := prepare(n) // parse/prepare BEFORE execution
if err != nil {
res.Err = err.Error()
if rerr := recordTerminal(ctx, ledger, runID, n, attempt, env, res, metrics, now); rerr != nil {
return res, rerr
}
return res, err // terminal row already written
}
res, err = execute(ctx, prepared)
if err != nil { res.Err = err.Error() }
if rerr := recordTerminal(ctx, ledger, runID, n, attempt, env, res, metrics, now); rerr != nil {
return res, rerr
}
return res, err
}
func recordTerminal(ctx context.Context, ledger *telemetry.Ledger, runID string,
n Node, attempt int, env []string, res RunResult,
metrics *NodeMetrics, now func() time.Time) error {
start := now().UTC()
end := start
_, err := ledger.Record(ctx, telemetry.Event{
RunID: runID, NodeID: n.ID, Attempt: attempt, Phase: "terminal",
Status: res.Status, StartedAt: start, EndedAt: &end,
IterationCount: nodeTotals(metrics), // 0 when unknown
Env: envMap(env), Error: res.Err,
})
return err
}
$ go build ./... && go vet ./...
$ go test ./... -count=1 -v
=== RUN TestMergeEnvRunnerOverridesProcess --- PASS
=== RUN TestLookupEnvUsesRunnerScope --- PASS
=== RUN TestParseFailureRecordsTerminalRow --- PASS
=== RUN TestUnknownIterationsStayZero --- PASS
=== RUN TestRealIterationsPersisted --- PASS
=== RUN TestThreeRunCanaryRetainsThreeRows --- PASS
=== RUN TestFirstWriteWinsOnConflictDoNothing --- PASS
=== RUN TestInsertOrReplaceWouldMutateHistory --- PASS
PASS
ok vtest/runner 0.005s
ok vtest/telemetry 0.005s
| Contract | Check | Result |
|---|---|---|
| Append-only | Duplicate Record returns inserted=false; Get equals first write |
PASS |
| No history rewrite | INSERT OR REPLACE mutates; production path uses DO NOTHING |
PASS |
| Runner context | Runner env overrides HERMES_RUN_ID; runner-only key resolvable |
PASS |
| Honest metrics | nil metrics -> iteration_count=0; real metrics persisted |
PASS |
| Failure coverage | prepare failure yields terminal/failed row |
PASS |
| Canary durability | 3 runs -> 3 rows, retained after close/re-open | PASS |
Run against the real repo:
$ go test ./... -count=1
$ golangci-lint run ./... # expect 0 issues
$ for i in 1 2 3; do <project> run --telemetry /tmp/canary.db --run-id "canary-$i" canary-node; done
$ sqlite3 /tmp/canary.db 'SELECT COUNT(*) FROM telemetry;'
3
$ rm -f /tmp/canary.checkpoint
$ sqlite3 /tmp/canary.db 'SELECT COUNT(*) FROM telemetry;'
3
| File | Change |
|---|---|
src/telemetry/telemetry.go |
Schema primary key on immutable identity; Record uses ON CONFLICT (...) DO NOTHING; no UPDATE/OR REPLACE path. |
src/telemetry/telemetry_test.go |
First-write-wins test + OR REPLACE mutation contrast test. |
src/runner/telemetry.go |
MergeEnv/LookupEnv merge runner env over process env. |
src/runner/runner.go |
All terminal paths (incl. pre-execution parse/prepare failures) write one terminal row; records merged env. |
src/runner/tsrun.go |
nodeTotals returns real metrics, 0 when unknown; never loop indices. |
src/runner/telemetry_test.go |
Env precedence, terminal-on-parse-failure, unknown/real totals, 3-run canary. |
# Evidence - Problem class: go-sqlite-append-only-telemetry-context - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-11T19:11:39.710Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "A scheduler-run telemetry ledger implementation can look complete while violating its core contract: INSERT OR REPLACE mutates supposedly append-only history, process-only environment lookup drops runner-scoped scheduler metadata, and node totals are incorrectly invented as iteration counts. Use first-write-wins ON CONFLICT DO NOTHING, merge runner Env over process Env, keep unknown iteration counts at zero until real metrics exist, and cover pre-execution parse/prepare failures as terminal rows.", "environment": "Linux; Go; SQLite telemetry ledger integrated with a DAG runner and scheduler-provided context", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-sqlite-append-only-telemetry-context", "provider": "openrouter", "solved_at": "2026-09-11T19:11:39.710Z", "version": "1.25.0"}