Nobody has started this yet — be first.
Business impact
Anyone managing jobs through the API today has no way to answer "when will this job next run?" without doing cron-expression math in their head or in a separate tool. That's a small but constant friction for every operator-facing surface that could show it: a dashboard listing jobs alongside their next fire time, a "this job hasn't run recently, is that expected?" sanity check, or simply GET /v1/jobs being genuinely useful for a human glancing at it instead of just machine-consumable.
Problem
pkg/cron/materializer.go's internal cron-parsing logic (parser, used by materializeCron) already knows how to compute a schedule's next occurrence, but that capability isn't exposed as a reusable, exported function -- it's inlined into the materializer's own catch-up loop. NextOccurrence is a placeholder that panics with "TODO(ticket-E4): NextOccurrence not implemented".
Current behavior
Calling cron.NextOccurrence panics instead of returning a computed next-fire time.
Expected behavior
cron.NextOccurrence(cronExpr, from) returns the next time the given cron expression fires at or after from, so the API layer can eventually expose it (e.g. a next_scheduled_for field on GET /v1/jobs) without duplicating cron-parsing logic.
Steps to reproduce
Why this matters
This is the same underlying capability materializeCron already uses (parser.Parse + schedule.Next), just extracted into a small, independently testable, reusable function instead of being locked inside the materializer's private loop.
Suggested approach
Look at materializeCron's use of parser.Parse(*job.CronExpr) followed by schedule.Next(from) for the exact pattern to reuse.
Acceptance criteria
Verification
go test ./tickets/tests/... -run TestTicket11 -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
Sign in to create it automatically, or do it yourself:
$git checkout -b feat/next-occurrenceFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/next-occurrenceSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign inhttp://localhost:8081app-1http://localhost:8082app-2http://localhost:8090curl localhost:8081/healthzcurl localhost:8081/readyzWork the tickets in tickets/docs/ (ordered easy → hard); each names one Go test in tickets/tests/. Most tickets need a real Postgres (tickets 4, 11, and 18 are pure-function tests and do not):
export TEST_DATABASE_URL="postgresql://chronos:chronos@localhost:5432/chronos?sslmode=disable"
go test ./tickets/tests/... -run TestTicket08 -v # a single ticket
./tickets/run_tickets.sh # all 20, clean pass/fail summary
Use -race when working on tickets 15, 16, or 17 (the concurrency ones) -- run_tickets.sh already does this for every ticket. Tickets 15 and 16 are adjacent bugs in the same function (pkg/leader/leader.go's lock-release path); fix ticket 16 first, since ticket 15's test keeps failing for ticket 16's reason until that one is fixed too.
Level 2
Implement a feature
Extend the system within its own patterns.