Files
the-custodian/docs/hourly-recently-on-scope-runbook.md

3.6 KiB

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:

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:

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:

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:

curl -s "http://127.0.0.1:8000/domains/custodian/recently-on-scope/" \
  | python3 -m json.tool

Read a report:

curl -s "http://127.0.0.1:8000/domains/custodian/recently-on-scope/<report_id>"

Default report directory:

~/state-hub/reports/recently-on-scope/<domain_slug>/

Manual Batch Canary

Before enabling the hourly schedule, run:

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.