Add hourly RecentlyOnScope activity definition
This commit is contained in:
85
activity-definitions/hourly-recently-on-scope.md
Normal file
85
activity-definitions/hourly-recently-on-scope.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
id: "d104348c-d792-4377-943c-70a31e81a9bc"
|
||||||
|
name: "Hourly RecentlyOnScope Reports"
|
||||||
|
type: activity-definition
|
||||||
|
version: "1.0"
|
||||||
|
enabled: false
|
||||||
|
owner: custodian
|
||||||
|
governance: custodian
|
||||||
|
status: draft
|
||||||
|
created: "2026-05-22"
|
||||||
|
trigger:
|
||||||
|
type: cron
|
||||||
|
cron_expression: "0 * * * *"
|
||||||
|
timezone: Europe/Berlin
|
||||||
|
misfire_policy: skip
|
||||||
|
context_sources:
|
||||||
|
- type: state-hub
|
||||||
|
query: recently_on_scope_hourly
|
||||||
|
required: true
|
||||||
|
params:
|
||||||
|
range: "1h"
|
||||||
|
active_only: true
|
||||||
|
include_attention: false
|
||||||
|
bind_to: context.recently_on_scope_hourly
|
||||||
|
---
|
||||||
|
|
||||||
|
# ActivityDefinition: Hourly RecentlyOnScope Reports
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
This definition is the activity-core handoff point for
|
||||||
|
`CUST-WP-0046 - Activity-Core Hourly RecentlyOnScope Reports`.
|
||||||
|
|
||||||
|
It schedules a deterministic State Hub batch run that generates
|
||||||
|
RecentlyOnScope reports for every active domain with qualifying activity in the
|
||||||
|
last hour. State Hub owns active-domain selection and report rendering;
|
||||||
|
activity-core owns the hourly schedule and ActivityRun audit trail.
|
||||||
|
|
||||||
|
## Runner Status
|
||||||
|
|
||||||
|
This definition is intentionally `enabled: false` until the manual canary
|
||||||
|
passes.
|
||||||
|
|
||||||
|
Cutover boundary:
|
||||||
|
|
||||||
|
- Codex app automation remains a fallback until `CUST-WP-0046-T06`.
|
||||||
|
- This activity-core definition becomes the primary hourly reporting substrate
|
||||||
|
only after one manual run and one scheduled run leave expected evidence.
|
||||||
|
- Do not run a Codex fallback and this activity-core hourly routine as parallel
|
||||||
|
primary runners.
|
||||||
|
|
||||||
|
## Trigger
|
||||||
|
|
||||||
|
Hourly at minute 0 in `Europe/Berlin`, with `misfire_policy: skip`.
|
||||||
|
|
||||||
|
If the activity-core host is offline at the top of the hour, this routine
|
||||||
|
skips the missed run rather than replaying a burst of stale reports after the
|
||||||
|
host returns.
|
||||||
|
|
||||||
|
## Deterministic State Hub Invocation
|
||||||
|
|
||||||
|
The `recently_on_scope_hourly` State Hub context resolver issues:
|
||||||
|
|
||||||
|
- `POST /recently-on-scope/hourly`
|
||||||
|
- payload: `{"range": "1h", "active_only": true, "include_attention": false}`
|
||||||
|
|
||||||
|
The context source is marked `required: true`. A failed State Hub call fails
|
||||||
|
the activity-core workflow visibly instead of silently binding an empty
|
||||||
|
context. On success, the response is stored in the ActivityRun
|
||||||
|
`context_snapshot` under `recently_on_scope_hourly`.
|
||||||
|
|
||||||
|
State Hub also records a compact progress event with event type
|
||||||
|
`recently_on_scope_hourly`, including generated, skipped, and failed domain
|
||||||
|
metadata.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
The run should produce:
|
||||||
|
|
||||||
|
- one State Hub progress event with `event_type: recently_on_scope_hourly`
|
||||||
|
- one report file per active domain with qualifying activity
|
||||||
|
- no report for inactive or quiet domains unless State Hub is explicitly
|
||||||
|
configured otherwise
|
||||||
|
- one activity-core ActivityRun containing the batch response metadata
|
||||||
|
- no LLM call and no direct workplan or canon edits
|
||||||
137
docs/hourly-recently-on-scope-runbook.md
Normal file
137
docs/hourly-recently-on-scope-runbook.md
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
# 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/<report_id>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Default report directory:
|
||||||
|
|
||||||
|
```text
|
||||||
|
~/state-hub/reports/recently-on-scope/<domain_slug>/
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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.
|
||||||
@@ -4,7 +4,7 @@ type: workplan
|
|||||||
title: "Activity-Core Hourly RecentlyOnScope Reports"
|
title: "Activity-Core Hourly RecentlyOnScope Reports"
|
||||||
domain: custodian
|
domain: custodian
|
||||||
repo: the-custodian
|
repo: the-custodian
|
||||||
status: ready
|
status: active
|
||||||
owner: codex
|
owner: codex
|
||||||
topic_slug: custodian
|
topic_slug: custodian
|
||||||
planning_priority: high
|
planning_priority: high
|
||||||
@@ -105,7 +105,7 @@ Preferred path:
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: CUST-WP-0046-T01
|
id: CUST-WP-0046-T01
|
||||||
status: todo
|
status: in_progress
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "99e16a50-9775-4520-b343-f52fda0b67ec"
|
state_hub_task_id: "99e16a50-9775-4520-b343-f52fda0b67ec"
|
||||||
```
|
```
|
||||||
@@ -130,7 +130,7 @@ paused/deleted.
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: CUST-WP-0046-T02
|
id: CUST-WP-0046-T02
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
depends_on: [CUST-WP-0046-T01]
|
depends_on: [CUST-WP-0046-T01]
|
||||||
state_hub_task_id: "c5004c0b-a261-407c-9376-a33883e054bf"
|
state_hub_task_id: "c5004c0b-a261-407c-9376-a33883e054bf"
|
||||||
@@ -163,7 +163,7 @@ behavior, report idempotency, partial failures, and report metadata response.
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: CUST-WP-0046-T03
|
id: CUST-WP-0046-T03
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
depends_on: [CUST-WP-0046-T02]
|
depends_on: [CUST-WP-0046-T02]
|
||||||
state_hub_task_id: "a33b379f-56ba-47d0-b73c-3e724b1c5d45"
|
state_hub_task_id: "a33b379f-56ba-47d0-b73c-3e724b1c5d45"
|
||||||
@@ -188,7 +188,7 @@ endpoint and record the result under test.
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: CUST-WP-0046-T04
|
id: CUST-WP-0046-T04
|
||||||
status: todo
|
status: in_progress
|
||||||
priority: high
|
priority: high
|
||||||
depends_on: [CUST-WP-0046-T03]
|
depends_on: [CUST-WP-0046-T03]
|
||||||
state_hub_task_id: "dcb20f5a-c446-48d6-b810-84de365c22fd"
|
state_hub_task_id: "dcb20f5a-c446-48d6-b810-84de365c22fd"
|
||||||
@@ -215,7 +215,7 @@ paused Temporal schedule while disabled.
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: CUST-WP-0046-T05
|
id: CUST-WP-0046-T05
|
||||||
status: todo
|
status: in_progress
|
||||||
priority: high
|
priority: high
|
||||||
depends_on: [CUST-WP-0046-T04]
|
depends_on: [CUST-WP-0046-T04]
|
||||||
state_hub_task_id: "f5c0cf64-a8e9-4d8c-bd86-ca58cbf132c2"
|
state_hub_task_id: "f5c0cf64-a8e9-4d8c-bd86-ca58cbf132c2"
|
||||||
@@ -245,10 +245,11 @@ Done when both manual and scheduled canaries leave complete evidence.
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: CUST-WP-0046-T06
|
id: CUST-WP-0046-T06
|
||||||
status: todo
|
status: blocked
|
||||||
priority: high
|
priority: high
|
||||||
depends_on: [CUST-WP-0046-T05]
|
depends_on: [CUST-WP-0046-T05]
|
||||||
state_hub_task_id: "2a46a6c8-4d3e-4064-a935-c90ca0c76a6d"
|
state_hub_task_id: "2a46a6c8-4d3e-4064-a935-c90ca0c76a6d"
|
||||||
|
blocking_reason: "Waiting for manual and scheduled activity-core canaries before retiring the Codex app fallback."
|
||||||
```
|
```
|
||||||
|
|
||||||
Remove the Codex app automation fallback from the operating path.
|
Remove the Codex app automation fallback from the operating path.
|
||||||
@@ -270,7 +271,7 @@ the owned activity-core schedule has verified evidence.
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: CUST-WP-0046-T07
|
id: CUST-WP-0046-T07
|
||||||
status: todo
|
status: done
|
||||||
priority: medium
|
priority: medium
|
||||||
depends_on: [CUST-WP-0046-T05]
|
depends_on: [CUST-WP-0046-T05]
|
||||||
state_hub_task_id: "01066ff8-f591-43f6-99e6-d2f61654e590"
|
state_hub_task_id: "01066ff8-f591-43f6-99e6-d2f61654e590"
|
||||||
@@ -292,6 +293,64 @@ Runbook should include:
|
|||||||
Done when the operator can verify hourly report health from State Hub and
|
Done when the operator can verify hourly report health from State Hub and
|
||||||
activity-core telemetry alone.
|
activity-core telemetry alone.
|
||||||
|
|
||||||
|
## Implementation Evidence - 2026-05-22
|
||||||
|
|
||||||
|
Implemented pieces:
|
||||||
|
|
||||||
|
- State Hub now exposes `POST /recently-on-scope/hourly`.
|
||||||
|
- State Hub batch generation reuses the existing RecentlyOnScope collector,
|
||||||
|
renderer, report id, and report directory.
|
||||||
|
- The batch endpoint selects domains by qualifying activity in the requested
|
||||||
|
window: progress events, decisions, updated workstreams, or updated tasks.
|
||||||
|
- Domains with only registered repositories are skipped; domains with open
|
||||||
|
human-intervention items can be included by setting `include_attention: true`.
|
||||||
|
- The batch endpoint records one `recently_on_scope_hourly` progress event with
|
||||||
|
generated, skipped, and failed domain metadata.
|
||||||
|
- activity-core has a reusable State Hub resolver query
|
||||||
|
`recently_on_scope_hourly` that POSTs to the batch endpoint.
|
||||||
|
- activity-core context sources can now be marked `required: true`; required
|
||||||
|
resolver failures fail the workflow instead of silently binding `{}`.
|
||||||
|
- Custodian now owns
|
||||||
|
`activity-definitions/hourly-recently-on-scope.md`, disabled until canary.
|
||||||
|
- Operator verification notes live in
|
||||||
|
`docs/hourly-recently-on-scope-runbook.md`.
|
||||||
|
|
||||||
|
Verification:
|
||||||
|
|
||||||
|
- State Hub:
|
||||||
|
`/home/worsch/.local/bin/uv run pytest tests/test_recently_on_scope.py`
|
||||||
|
passed with 11 tests.
|
||||||
|
- State Hub:
|
||||||
|
`/home/worsch/.local/bin/uv run pytest tests/test_recently_on_scope.py tests/test_mcp_smoke.py::TestAddProgressEvent`
|
||||||
|
passed with 14 tests.
|
||||||
|
- activity-core:
|
||||||
|
`/home/worsch/.local/bin/uv run pytest tests/test_state_hub_context_resolver.py tests/test_sync_activity_definitions.py tests/test_schedule_lifecycle.py`
|
||||||
|
passed with 19 tests.
|
||||||
|
- activity-core parser scan with
|
||||||
|
`ACTIVITY_DEFINITION_DIRS=/home/worsch/the-custodian` found
|
||||||
|
`Hourly RecentlyOnScope Reports`.
|
||||||
|
|
||||||
|
Local canary evidence:
|
||||||
|
|
||||||
|
- Direct State Hub batch canary generated reports for `custodian` and
|
||||||
|
`markitect`, skipped 9 quiet active domains, and had no failed domains.
|
||||||
|
Progress event: `ff1e845f-df02-476e-a3f3-fb912e4f32a8`.
|
||||||
|
- Direct activity-core resolver canary invoked the same State Hub batch endpoint
|
||||||
|
and generated reports for `custodian` and `markitect`, skipped 9 domains, and
|
||||||
|
had no failed domains.
|
||||||
|
Progress event: `1ff091c3-227c-4a85-b5e2-172ba45a2676`.
|
||||||
|
|
||||||
|
Remaining gates:
|
||||||
|
|
||||||
|
- T01 remains in progress until the deployed activity-core API/worker/Temporal
|
||||||
|
schedule path is checked from the operator host.
|
||||||
|
- T04 remains in progress until the definition is synced into the live
|
||||||
|
activity-core DB and appears as a disabled/paused Temporal schedule.
|
||||||
|
- T05 remains in progress until a real `RunActivityWorkflow` produces an
|
||||||
|
ActivityRun and one scheduled hourly canary completes.
|
||||||
|
- T06 is blocked until T05 passes; the Codex app fallback should not be paused
|
||||||
|
or deleted before then.
|
||||||
|
|
||||||
## Acceptance Criteria
|
## Acceptance Criteria
|
||||||
|
|
||||||
- Hourly RecentlyOnScope reports are generated by activity-core, not Codex app
|
- Hourly RecentlyOnScope reports are generated by activity-core, not Codex app
|
||||||
|
|||||||
Reference in New Issue
Block a user