Skip to content

fix: batch-1 bug sweep — runs DELETE status lie, cleanup dry-run parity, subagent registry/relay - #170

Merged
jkyberneees merged 3 commits into
mainfrom
fix/bug-hunt-b1
Sep 1, 2026
Merged

fix: batch-1 bug sweep — runs DELETE status lie, cleanup dry-run parity, subagent registry/relay#170
jkyberneees merged 3 commits into
mainfrom
fix/bug-hunt-b1

Conversation

@jkyberneees

Copy link
Copy Markdown
Contributor

Batch 1 of the bug-hunt sweep (5 bugs, every fix RED-first: failing test observed before the fix, green after).

Bugs fixed

  1. DELETE /api/runs/{id} lied about terminal runs (serve_runs.go) — the handler called cancelRun unconditionally and answered the hardcoded status "cancelled", even for runs that had already completed or failed; cancelRun → finish also re-stamped EndedAt on terminal runs. Terminal runs are now left untouched; the response echoes the real status with idle: true, matching POST /api/runs/{id}/cancel.

  2. cleanup --dry-run never previewed artifact deletions — the collector had no artifacts category, so it could report "storage is clean" while the real sweep deleted ~/.odek/artifacts/<session_id>/ subtrees older than ArtifactsMaxAgeHours (enabled by default). Artifact subtrees are now previewed with the same duration-based cutoff sweepArtifacts uses.

  3. cleanup --dry-run log list omitted serve.log — the real rotateLogs rotates {telegram, schedule, serve}.log; the preview only knew two. The list is now shared via maintenance.LogRotationNames() so preview and rotation can never drift again.

  4. Sub-agent registry evicted LIVE entries (wire-v2) — ring overflow dropped entries[0] regardless of phase; a running task's next progress record then auto-created a hollow entry without RunKey, making it invisible to GET /api/subagents?run_key=… (the reload-restore path). Eviction now prefers the oldest finished entry, and subagentRegistryUpdate stamps recreated entries with the relay's runKey.

  5. Done relay clobbered child-reported success (wire-v2) — the parent-side relay (fired when a child's framed result never arrived/parsed) unconditionally overwrote the terminal state and bumped failed: a task the child reported as success showed failed-with-cost and both lifetime counters counted it. First terminal report now wins.

Verification

  • 5 new RED-first regression tests (one per bug), observed failing before each fix
  • go build ./... clean; go test ./cmd/odek/ ./internal/maintenance/ green
  • go vet clean; golangci-lint 0 issues; -race clean on maintenance + scoped cmd/odek suites

DELETE /api/runs/{id} called cancelRun unconditionally and answered the
hardcoded status "cancelled" — even for runs that had already completed
or failed. cancelRun → finish also re-stamped EndedAt on terminal runs.
Terminal runs are now left untouched and the response echoes the run's
real status with idle=true, matching POST /api/runs/{id}/cancel.

RED-first regression test: TestRunDelete_TerminalRunReportsRealStatus.
Two preview gaps made 'odek cleanup --dry-run' lie about what the real
sweep would remove:

- the dry-run collector had no artifacts category, so it could report
  'storage is clean' while maintenance.Sweep deleted
  ~/.odek/artifacts/<session_id>/ subtrees older than
  ArtifactsMaxAgeHours (on by default). Artifact subtrees are now
  previewed via artifactCandidates, with the same duration-based cutoff
  sweepArtifacts uses.
- the dry-run log list was {schedule.log, telegram.log} while
  rotateLogs also rotates serve.log. The list is now shared via
  maintenance.LogRotationNames so the two can never drift again.

RED-first regression tests: TestCleanupDryRun_PreviewsArtifactSubtrees,
TestCleanupDryRun_IncludesServeLog.
…inal reports

Two wire-v2 telemetry bugs:

- Ring eviction dropped entries[0] regardless of phase, so a
  still-running sub-agent could be evicted under ring pressure; its
  next progress record then auto-created a hollow entry without RunKey,
  making the task invisible to GET /api/subagents?run_key=... — the
  reload-restore path the registry exists for. Eviction now prefers the
  oldest finished entry, and subagentRegistryUpdate stamps recreated
  entries with the relay's runKey.
- The parent done relay (fired only for children whose framed result
  never arrived or never parsed) unconditionally overwrote the terminal
  state and bumped the failed counter. A child that reported success on
  its own stream showed as failed-with-cost, and both lifetime counters
  counted the same task. First terminal report now wins.

RED-first regression tests: TestSubagentRegistry_EvictionKeepsLiveEntriesVisible,
TestSubagentDoneRelay_DoesNotClobberChildReportedSuccess.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
odek 268d4f6 Commit Preview URL

Branch Preview URL
Sep 01 2026, 06:41 AM

@jkyberneees
jkyberneees merged commit d18cf93 into main Sep 1, 2026
10 checks passed
@jkyberneees
jkyberneees deleted the fix/bug-hunt-b1 branch September 1, 2026 06:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant