# Hourly RecentlyOnScope Runbook ## Purpose This runbook answers whether the hourly RecentlyOnScope routine ran without opening Codex Desktop. The intended steady state is: - activity-core owns the hourly schedule and ActivityRun audit trail. - State Hub owns active-domain selection, report generation, report storage, and the `recently_on_scope_hourly` progress event. - Codex app automation is not part of the primary hourly reporting path after `CUST-WP-0046-T06`. ## Schedule Check From the activity-core host, confirm the definition is synced and the Temporal schedule exists: ```bash cd ~/activity-core ACTIVITY_DEFINITION_DIRS=/home/worsch/the-custodian make sync-activity-definitions make sync-schedules ``` Expected definition: - name: `Hourly RecentlyOnScope Reports` - trigger: `0 * * * *` - timezone: `Europe/Berlin` - misfire policy: `skip` - enabled: `false` until manual canary passes, then `true` ## Temporal Check Use the Temporal UI or CLI on the activity-core host to inspect schedules and recent workflows. Look for: - a schedule for `Hourly RecentlyOnScope Reports` - the most recent `RunActivityWorkflow` - a successful workflow result with `tasks_spawned: 0` A failure in the required State Hub context source should fail the workflow visibly rather than recording an empty context. ## ActivityRun Check Query the activity-core database for the most recent run of the hourly definition: ```sql select run_id, fired_at, scheduled_for, context_snapshot->'recently_on_scope_hourly' as batch_result from activity_runs where activity_id = 'd104348c-d792-4377-943c-70a31e81a9bc' order by fired_at desc limit 5; ``` The `batch_result` should include `generated`, `skipped`, `failed`, and `progress_event_id`. ## State Hub Progress Check Ask State Hub for the latest batch progress events: ```bash curl -s "http://127.0.0.1:8000/progress/?event_type=recently_on_scope_hourly&limit=5" \ | python3 -m json.tool ``` Expected: - `event_type`: `recently_on_scope_hourly` - `author`: `state-hub` - `detail.generated`: domains with qualifying activity - `detail.skipped`: quiet active domains - `detail.failed`: empty in the healthy case ## Report Check List reports for a domain: ```bash curl -s "http://127.0.0.1:8000/domains/custodian/recently-on-scope/" \ | python3 -m json.tool ``` Read a report: ```bash curl -s "http://127.0.0.1:8000/domains/custodian/recently-on-scope/" ``` Default report directory: ```text ~/state-hub/reports/recently-on-scope// ``` ## Manual Batch Canary Before enabling the hourly schedule, run: ```bash curl -s -X POST "http://127.0.0.1:8000/recently-on-scope/hourly" \ -H "Content-Type: application/json" \ -d '{"range":"1h","active_only":true,"include_attention":false}' \ | python3 -m json.tool ``` Then trigger the activity-core path with the same payload and confirm an ActivityRun captures the batch response under `recently_on_scope_hourly`. ## Offline Behavior The schedule uses `misfire_policy: skip`. If the activity-core host is offline at the top of the hour, that hourly run is missed. When the host returns, activity-core should resume with the next hourly slot rather than replaying stale runs in a burst. ## Retention State Hub currently writes one Markdown report per domain and report id. Report ids are deterministic for exact windows and are replaced on rerun. The current implementation does not delete old reports automatically. Until a retention job exists, operators should treat the report directory as an append-only operational record and prune only after confirming that no audit or handoff references point at the target files.