# Resolver Spec: `discover_kaizen_scheduled_repos` **Status:** implemented in activity-core (`context_resolvers/kaizen.py`). This doc is the contract an activity-core implementer needs to add the context resolver that feeds the scheduled-agent ActivityDefinitions (ADR-005). ## Purpose Given the fleet roster and per-repo schedule manifests, emit one entry per `(repo, agent)` that is due to run, so ActivityDefinitions can `for_each` over the result. ## Signature ``` discover_kaizen_scheduled_repos( domain: str | None = None, # optional scope filter, e.g. "custodian" cadence: str | None = None, # optional: "daily" | "weekly" | "monthly" now: datetime | None = None, # injection point for testing ) -> { "scheduled_runs": list[ScheduledRun] } ``` Bound in a definition as: ```yaml context_sources: - type: resolver query: discover_kaizen_scheduled_repos params: domain: custodian cadence: weekly bind_to: context.scheduled_runs ``` ## Inputs (sources, in order) 1. **State Hub** `GET /repos/` (optionally filtered by `domain` and, when the v2 flag lands, `kaizen_schedule_enabled=true`). Yields `slug`, `host_paths`, `domain`. 2. **Repo checkout** at `host_paths[]`: read `.kaizen/schedule.yml`. Skip repos without the file. 3. **Validation**: run the equivalent of `kaizen-agentic schedule validate`. Skip (and log) repos whose schedule is invalid — never emit a bad entry. ## Output shape ```json { "scheduled_runs": [ { "repo": "kaizen-agentic", "root": "/home/worsch/kaizen-agentic", "agent": "coach", "cadence": "weekly", "cron": "0 9 * * 1", "timezone": "Europe/Berlin", "enabled": true, "prepare_command": "kaizen-agentic schedule prepare coach --target /home/worsch/kaizen-agentic" } ] } ``` ### `ScheduledRun` fields | Field | Source | Notes | |-------|--------|-------| | `repo` | hub `slug` | becomes `target_repo` on the created task | | `root` | `host_paths[]` | absolute checkout path on the runner | | `agent` | schedule.yml key | | | `cadence` | schedule.yml | | | `cron` | schedule.yml or definition default | per-repo override when present | | `timezone` | schedule.yml or definition default | | | `enabled` | schedule.yml (`true` only emitted) | disabled entries are filtered out | | `prepare_command` | derived | exact CLI the task should run | ## Filtering rules - Emit only entries with `enabled: true`. - When `cadence` param is set, emit only matching entries (lets each cron-bound definition select its own cadence slice). - When `cron` is present on the entry, it is the authoritative per-repo time; otherwise the definition's cron applies. ## Errors | Condition | Behavior | |-----------|----------| | Repo unreachable / path missing on host | Skip + log `repo_unreachable` | | `.kaizen/schedule.yml` absent | Skip silently (not opted in) | | schedule.yml invalid | Skip + log `schedule_invalid` with validation errors | | Hub unreachable | Fail the resolver run (no roster = no safe output) | The resolver must be **idempotent** and **side-effect free**: it reads, it does not write. Task creation happens in the ActivityDefinition rule, not here. ## Test fixtures - A repo with valid `.kaizen/schedule.yml` (coach enabled) → one entry. - A repo with the file but coach `enabled: false` → no entry. - A repo without the file → no entry. - A repo with an invalid schedule → no entry + logged error. ## Related - [state-hub-roster-fields.md](state-hub-roster-fields.md) - [schedule-schema.md](schedule-schema.md) - [activity-definitions/weekly-coach-orientation.md](activity-definitions/weekly-coach-orientation.md) - [ADR-005](../adr/ADR-005-scheduled-agent-execution.md)