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"
|
||||
domain: custodian
|
||||
repo: the-custodian
|
||||
status: ready
|
||||
status: active
|
||||
owner: codex
|
||||
topic_slug: custodian
|
||||
planning_priority: high
|
||||
@@ -105,7 +105,7 @@ Preferred path:
|
||||
|
||||
```task
|
||||
id: CUST-WP-0046-T01
|
||||
status: todo
|
||||
status: in_progress
|
||||
priority: high
|
||||
state_hub_task_id: "99e16a50-9775-4520-b343-f52fda0b67ec"
|
||||
```
|
||||
@@ -130,7 +130,7 @@ paused/deleted.
|
||||
|
||||
```task
|
||||
id: CUST-WP-0046-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
depends_on: [CUST-WP-0046-T01]
|
||||
state_hub_task_id: "c5004c0b-a261-407c-9376-a33883e054bf"
|
||||
@@ -163,7 +163,7 @@ behavior, report idempotency, partial failures, and report metadata response.
|
||||
|
||||
```task
|
||||
id: CUST-WP-0046-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
depends_on: [CUST-WP-0046-T02]
|
||||
state_hub_task_id: "a33b379f-56ba-47d0-b73c-3e724b1c5d45"
|
||||
@@ -188,7 +188,7 @@ endpoint and record the result under test.
|
||||
|
||||
```task
|
||||
id: CUST-WP-0046-T04
|
||||
status: todo
|
||||
status: in_progress
|
||||
priority: high
|
||||
depends_on: [CUST-WP-0046-T03]
|
||||
state_hub_task_id: "dcb20f5a-c446-48d6-b810-84de365c22fd"
|
||||
@@ -215,7 +215,7 @@ paused Temporal schedule while disabled.
|
||||
|
||||
```task
|
||||
id: CUST-WP-0046-T05
|
||||
status: todo
|
||||
status: in_progress
|
||||
priority: high
|
||||
depends_on: [CUST-WP-0046-T04]
|
||||
state_hub_task_id: "f5c0cf64-a8e9-4d8c-bd86-ca58cbf132c2"
|
||||
@@ -245,10 +245,11 @@ Done when both manual and scheduled canaries leave complete evidence.
|
||||
|
||||
```task
|
||||
id: CUST-WP-0046-T06
|
||||
status: todo
|
||||
status: blocked
|
||||
priority: high
|
||||
depends_on: [CUST-WP-0046-T05]
|
||||
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.
|
||||
@@ -270,7 +271,7 @@ the owned activity-core schedule has verified evidence.
|
||||
|
||||
```task
|
||||
id: CUST-WP-0046-T07
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
depends_on: [CUST-WP-0046-T05]
|
||||
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
|
||||
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
|
||||
|
||||
- Hourly RecentlyOnScope reports are generated by activity-core, not Codex app
|
||||
|
||||
Reference in New Issue
Block a user